Active Line Demo
Styling the current cursor line.
Repository: basco-johnkevin/laravelsnippets Branch: master Commit: 0a29988a9d24 Files: 615 Total size: 3.3 MB Directory structure: gitextract_pialv810/ ├── .gitattributes ├── .gitignore ├── app/ │ ├── LaraSnipp/ │ │ ├── Command/ │ │ │ └── CommentsCommand.php │ │ ├── Composer/ │ │ │ └── LayoutMasterComposer.php │ │ ├── LaraSnippServiceProvider.php │ │ ├── Mailer/ │ │ │ ├── Mailer.php │ │ │ └── UserMailer.php │ │ ├── Observer/ │ │ │ ├── ObserverServiceProvider.php │ │ │ ├── Snippet/ │ │ │ │ └── SnippetObserver.php │ │ │ └── User/ │ │ │ └── UserObserver.php │ │ ├── Repo/ │ │ │ ├── EloquentBaseRepository.php │ │ │ ├── RepoServiceProvider.php │ │ │ ├── Snippet/ │ │ │ │ ├── EloquentSnippetRepository.php │ │ │ │ └── SnippetRepositoryInterface.php │ │ │ ├── Tag/ │ │ │ │ ├── EloquentTagRepository.php │ │ │ │ └── TagRepositoryInterface.php │ │ │ └── User/ │ │ │ ├── EloquentUserRepository.php │ │ │ └── UserRepositoryInterface.php │ │ └── Service/ │ │ ├── Form/ │ │ │ ├── FormServiceProvider.php │ │ │ ├── Snippet/ │ │ │ │ ├── SnippetForm.php │ │ │ │ └── SnippetFormLaravelValidator.php │ │ │ └── User/ │ │ │ ├── UserForm.php │ │ │ └── UserFormLaravelValidator.php │ │ └── Validation/ │ │ ├── AbstractLaravelValidator.php │ │ └── ValidableInterface.php │ ├── commands/ │ │ └── .gitkeep │ ├── config/ │ │ ├── app.php │ │ ├── auth.php │ │ ├── cache.php │ │ ├── compile.php │ │ ├── database.php │ │ ├── disqus.php │ │ ├── mail.php │ │ ├── packages/ │ │ │ └── .gitkeep │ │ ├── purifier.php │ │ ├── queue.php │ │ ├── remote.php │ │ ├── session.php │ │ ├── site.php │ │ ├── testing/ │ │ │ ├── app.php │ │ │ ├── cache.php │ │ │ ├── database.php │ │ │ ├── mail.php │ │ │ └── session.php │ │ ├── view.php │ │ └── workbench.php │ ├── controllers/ │ │ ├── .gitkeep │ │ ├── Admin/ │ │ │ └── IndexController.php │ │ ├── AuthController.php │ │ ├── BaseController.php │ │ ├── HomeController.php │ │ ├── Member/ │ │ │ ├── SnippetController.php │ │ │ └── UserController.php │ │ ├── RemindersController.php │ │ ├── SnippetController.php │ │ ├── TagController.php │ │ ├── UserController.php │ │ └── website/ │ │ └── PagesController.php │ ├── database/ │ │ ├── migrations/ │ │ │ ├── .gitkeep │ │ │ ├── 2013_11_08_145020_create_snippets_table.php │ │ │ ├── 2013_12_05_122548_create_users_table.php │ │ │ ├── 2013_12_05_122952_add_author_id_in_snippets_table.php │ │ │ ├── 2013_12_08_055430_add_slug_and_activation_key_and_active_in_users_table.php │ │ │ ├── 2013_12_09_125456_drop_active_in_users_table.php │ │ │ ├── 2013_12_09_130122_add_active_in_users_table.php │ │ │ ├── 2013_12_10_112312_add_approved_in_snippets_table.php │ │ │ ├── 2013_12_10_132447_add_slug_in_snippets_table.php │ │ │ ├── 2013_12_11_012940_create_roles_table.php │ │ │ ├── 2013_12_11_013036_add_role_id_in_users_table.php │ │ │ ├── 2013_12_11_013559_add_description_credits_to_resource_deleted_at_in_snippets_table.php │ │ │ ├── 2013_12_11_014226_create_tags_table.php │ │ │ ├── 2013_12_11_014317_create_snippet_tag_table.php │ │ │ ├── 2013_12_11_103428_add_slug_in_tags_table.php │ │ │ ├── 2013_12_12_093641_add_remaining_columns_in_users_table.php │ │ │ ├── 2013_12_19_134131_create_password_reminders_table.php │ │ │ ├── 2014_01_04_072223_add_disqus_columns_to_snippets_table.php │ │ │ ├── 2014_01_06_212314_create_user_starred_table.php │ │ │ └── 2014_04_17_151653_add_remember_token_to_users_table.php │ │ └── seeds/ │ │ ├── .gitkeep │ │ ├── DatabaseSeeder.php │ │ ├── RoleSeeder.php │ │ └── TagSeeder.php │ ├── filters.php │ ├── lang/ │ │ └── en/ │ │ ├── pagination.php │ │ ├── reminders.php │ │ └── validation.php │ ├── libraries/ │ │ └── SiteHelpers.php │ ├── macros.php │ ├── models/ │ │ ├── BaseModel.php │ │ ├── Role.php │ │ ├── Snippet.php │ │ ├── Starred.php │ │ ├── Tag.php │ │ └── User.php │ ├── routes.php │ ├── start/ │ │ ├── artisan.php │ │ ├── global.php │ │ └── local.php │ ├── storage/ │ │ ├── .gitignore │ │ ├── cache/ │ │ │ └── .gitignore │ │ ├── logs/ │ │ │ └── .gitignore │ │ ├── meta/ │ │ │ └── .gitignore │ │ ├── sessions/ │ │ │ └── .gitignore │ │ └── views/ │ │ └── .gitignore │ ├── tests/ │ │ ├── TestCase.php │ │ ├── functional/ │ │ │ └── Controller/ │ │ │ ├── AuthControllerTest.php │ │ │ ├── HomeControllerTest.php │ │ │ ├── Member/ │ │ │ │ ├── SnippetControllerTest.php │ │ │ │ └── UserControllerTest.php │ │ │ ├── SnippetControllerTest.php │ │ │ ├── TagControllerTest.php │ │ │ └── UserControllerTest.php │ │ ├── integration/ │ │ │ ├── Model/ │ │ │ │ └── UserModelTest.php │ │ │ └── Repo/ │ │ │ ├── EloquentSnippetRepositoryTest.php │ │ │ └── EloquentUserRepositoryTest.php │ │ └── unit/ │ │ └── Model/ │ │ └── UserModelTest.php │ └── views/ │ ├── admin/ │ │ ├── index.blade.php │ │ ├── layouts/ │ │ │ └── master.blade.php │ │ └── partials/ │ │ └── navbar.blade.php │ ├── auth/ │ │ ├── login.blade.php │ │ └── signup.blade.php │ ├── emails/ │ │ └── auth/ │ │ ├── activate.blade.php │ │ └── reminder.blade.php │ ├── layouts/ │ │ └── master.blade.php │ ├── member/ │ │ ├── snippets/ │ │ │ ├── create.blade.php │ │ │ └── edit.blade.php │ │ └── users/ │ │ └── dashboard.blade.php │ ├── partials/ │ │ ├── footer.blade.php │ │ ├── header.blade.php │ │ ├── notifications.blade.php │ │ ├── pagination.blade.php │ │ ├── search-narrow.blade.php │ │ ├── search.blade.php │ │ ├── searchForm.blade.php │ │ ├── sidebars/ │ │ │ ├── default.blade.php │ │ │ ├── snippet.blade.php │ │ │ └── widgets/ │ │ │ ├── author.blade.php │ │ │ ├── categories.blade.php │ │ │ ├── social.blade.php │ │ │ └── top-contributors.blade.php │ │ └── snippets.php │ ├── password/ │ │ ├── remind.blade.php │ │ └── reset.blade.php │ ├── snippets/ │ │ ├── index.blade.php │ │ └── show.blade.php │ ├── tags/ │ │ └── snippets.blade.php │ ├── users/ │ │ ├── index.blade.php │ │ ├── profile.blade.php │ │ ├── settings.blade.php │ │ └── snippets.blade.php │ └── website/ │ └── pages/ │ ├── 404.blade.php │ ├── index.blade.php │ └── roadmap.blade.php ├── artisan ├── bootstrap/ │ ├── autoload.php │ ├── paths.php │ └── start.php ├── composer.json ├── gulpfile.js ├── package.json ├── phpunit.xml ├── public/ │ ├── .htaccess │ ├── administration/ │ │ ├── css/ │ │ │ ├── sb-admin-2.css │ │ │ └── timeline.css │ │ └── js/ │ │ └── sb-admin-2.js │ ├── assets/ │ │ ├── coffee/ │ │ │ ├── common.coffee │ │ │ └── snippet.coffee │ │ ├── css/ │ │ │ └── styles.css │ │ ├── js/ │ │ │ ├── common.js │ │ │ ├── snippet.js │ │ │ └── vendors/ │ │ │ └── json2/ │ │ │ └── json2.js │ │ └── scss/ │ │ ├── core/ │ │ │ ├── _band.scss │ │ │ ├── _global.scss │ │ │ ├── _mixins.scss │ │ │ └── _variables.scss │ │ ├── pages/ │ │ │ ├── _profiles.scss │ │ │ └── _snippet.scss │ │ ├── partials/ │ │ │ ├── _breadcrumbs.scss │ │ │ ├── _footer.scss │ │ │ ├── _nav-bar.scss │ │ │ ├── _pagination.scss │ │ │ ├── _search-band.scss │ │ │ ├── _sidebar.scss │ │ │ └── _snippets.scss │ │ └── styles.scss │ ├── index.php │ ├── packages/ │ │ ├── .gitkeep │ │ ├── chosen_v1.0.0/ │ │ │ ├── chosen.css │ │ │ ├── chosen.jquery.js │ │ │ ├── chosen.proto.js │ │ │ ├── docsupport/ │ │ │ │ ├── prism.css │ │ │ │ ├── prism.js │ │ │ │ └── style.css │ │ │ ├── index.html │ │ │ ├── index.proto.html │ │ │ └── options.html │ │ ├── codemirror-3.19/ │ │ │ ├── .gitattributes │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── AUTHORS │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── addon/ │ │ │ │ ├── comment/ │ │ │ │ │ ├── comment.js │ │ │ │ │ └── continuecomment.js │ │ │ │ ├── dialog/ │ │ │ │ │ ├── dialog.css │ │ │ │ │ └── dialog.js │ │ │ │ ├── display/ │ │ │ │ │ ├── fullscreen.css │ │ │ │ │ ├── fullscreen.js │ │ │ │ │ └── placeholder.js │ │ │ │ ├── edit/ │ │ │ │ │ ├── closebrackets.js │ │ │ │ │ ├── closetag.js │ │ │ │ │ ├── continuelist.js │ │ │ │ │ ├── matchbrackets.js │ │ │ │ │ ├── matchtags.js │ │ │ │ │ └── trailingspace.js │ │ │ │ ├── fold/ │ │ │ │ │ ├── brace-fold.js │ │ │ │ │ ├── comment-fold.js │ │ │ │ │ ├── foldcode.js │ │ │ │ │ ├── foldgutter.css │ │ │ │ │ ├── foldgutter.js │ │ │ │ │ ├── indent-fold.js │ │ │ │ │ └── xml-fold.js │ │ │ │ ├── hint/ │ │ │ │ │ ├── anyword-hint.js │ │ │ │ │ ├── css-hint.js │ │ │ │ │ ├── html-hint.js │ │ │ │ │ ├── javascript-hint.js │ │ │ │ │ ├── pig-hint.js │ │ │ │ │ ├── python-hint.js │ │ │ │ │ ├── show-hint.css │ │ │ │ │ ├── show-hint.js │ │ │ │ │ ├── sql-hint.js │ │ │ │ │ └── xml-hint.js │ │ │ │ ├── lint/ │ │ │ │ │ ├── coffeescript-lint.js │ │ │ │ │ ├── css-lint.js │ │ │ │ │ ├── javascript-lint.js │ │ │ │ │ ├── json-lint.js │ │ │ │ │ ├── lint.css │ │ │ │ │ └── lint.js │ │ │ │ ├── merge/ │ │ │ │ │ ├── dep/ │ │ │ │ │ │ └── diff_match_patch.js │ │ │ │ │ ├── merge.css │ │ │ │ │ └── merge.js │ │ │ │ ├── mode/ │ │ │ │ │ ├── loadmode.js │ │ │ │ │ ├── multiplex.js │ │ │ │ │ ├── multiplex_test.js │ │ │ │ │ └── overlay.js │ │ │ │ ├── runmode/ │ │ │ │ │ ├── colorize.js │ │ │ │ │ ├── runmode-standalone.js │ │ │ │ │ ├── runmode.js │ │ │ │ │ └── runmode.node.js │ │ │ │ ├── scroll/ │ │ │ │ │ └── scrollpastend.js │ │ │ │ ├── search/ │ │ │ │ │ ├── match-highlighter.js │ │ │ │ │ ├── search.js │ │ │ │ │ └── searchcursor.js │ │ │ │ ├── selection/ │ │ │ │ │ ├── active-line.js │ │ │ │ │ └── mark-selection.js │ │ │ │ ├── tern/ │ │ │ │ │ ├── tern.css │ │ │ │ │ ├── tern.js │ │ │ │ │ └── worker.js │ │ │ │ └── wrap/ │ │ │ │ └── hardwrap.js │ │ │ ├── bin/ │ │ │ │ ├── authors.sh │ │ │ │ ├── compress │ │ │ │ ├── lint │ │ │ │ └── source-highlight │ │ │ ├── bower.json │ │ │ ├── demo/ │ │ │ │ ├── activeline.html │ │ │ │ ├── anywordhint.html │ │ │ │ ├── bidi.html │ │ │ │ ├── btree.html │ │ │ │ ├── buffers.html │ │ │ │ ├── changemode.html │ │ │ │ ├── closebrackets.html │ │ │ │ ├── closetag.html │ │ │ │ ├── complete.html │ │ │ │ ├── emacs.html │ │ │ │ ├── folding.html │ │ │ │ ├── fullscreen.html │ │ │ │ ├── hardwrap.html │ │ │ │ ├── html5complete.html │ │ │ │ ├── indentwrap.html │ │ │ │ ├── lint.html │ │ │ │ ├── loadmode.html │ │ │ │ ├── marker.html │ │ │ │ ├── markselection.html │ │ │ │ ├── matchhighlighter.html │ │ │ │ ├── matchtags.html │ │ │ │ ├── merge.html │ │ │ │ ├── multiplex.html │ │ │ │ ├── mustache.html │ │ │ │ ├── placeholder.html │ │ │ │ ├── preview.html │ │ │ │ ├── resize.html │ │ │ │ ├── runmode.html │ │ │ │ ├── search.html │ │ │ │ ├── spanaffectswrapping_shim.html │ │ │ │ ├── tern.html │ │ │ │ ├── theme.html │ │ │ │ ├── trailingspace.html │ │ │ │ ├── variableheight.html │ │ │ │ ├── vim.html │ │ │ │ ├── visibletabs.html │ │ │ │ ├── widget.html │ │ │ │ └── xmlcomplete.html │ │ │ ├── doc/ │ │ │ │ ├── activebookmark.js │ │ │ │ ├── compress.html │ │ │ │ ├── docs.css │ │ │ │ ├── internals.html │ │ │ │ ├── manual.html │ │ │ │ ├── realworld.html │ │ │ │ ├── releases.html │ │ │ │ ├── reporting.html │ │ │ │ ├── upgrade_v2.2.html │ │ │ │ └── upgrade_v3.html │ │ │ ├── index.html │ │ │ ├── keymap/ │ │ │ │ ├── emacs.js │ │ │ │ ├── extra.js │ │ │ │ └── vim.js │ │ │ ├── lib/ │ │ │ │ ├── codemirror.css │ │ │ │ └── codemirror.js │ │ │ ├── mode/ │ │ │ │ ├── apl/ │ │ │ │ │ ├── apl.js │ │ │ │ │ └── index.html │ │ │ │ ├── asterisk/ │ │ │ │ │ ├── asterisk.js │ │ │ │ │ └── index.html │ │ │ │ ├── clike/ │ │ │ │ │ ├── clike.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── scala.html │ │ │ │ ├── clojure/ │ │ │ │ │ ├── clojure.js │ │ │ │ │ └── index.html │ │ │ │ ├── cobol/ │ │ │ │ │ ├── cobol.js │ │ │ │ │ └── index.html │ │ │ │ ├── coffeescript/ │ │ │ │ │ ├── coffeescript.js │ │ │ │ │ └── index.html │ │ │ │ ├── commonlisp/ │ │ │ │ │ ├── commonlisp.js │ │ │ │ │ └── index.html │ │ │ │ ├── css/ │ │ │ │ │ ├── css.js │ │ │ │ │ ├── index.html │ │ │ │ │ ├── scss.html │ │ │ │ │ ├── scss_test.js │ │ │ │ │ └── test.js │ │ │ │ ├── d/ │ │ │ │ │ ├── d.js │ │ │ │ │ └── index.html │ │ │ │ ├── diff/ │ │ │ │ │ ├── diff.js │ │ │ │ │ └── index.html │ │ │ │ ├── dtd/ │ │ │ │ │ ├── dtd.js │ │ │ │ │ └── index.html │ │ │ │ ├── ecl/ │ │ │ │ │ ├── ecl.js │ │ │ │ │ └── index.html │ │ │ │ ├── eiffel/ │ │ │ │ │ ├── eiffel.js │ │ │ │ │ └── index.html │ │ │ │ ├── erlang/ │ │ │ │ │ ├── erlang.js │ │ │ │ │ └── index.html │ │ │ │ ├── fortran/ │ │ │ │ │ ├── fortran.js │ │ │ │ │ └── index.html │ │ │ │ ├── gas/ │ │ │ │ │ ├── gas.js │ │ │ │ │ └── index.html │ │ │ │ ├── gfm/ │ │ │ │ │ ├── gfm.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── gherkin/ │ │ │ │ │ ├── gherkin.js │ │ │ │ │ └── index.html │ │ │ │ ├── go/ │ │ │ │ │ ├── go.js │ │ │ │ │ └── index.html │ │ │ │ ├── groovy/ │ │ │ │ │ ├── groovy.js │ │ │ │ │ └── index.html │ │ │ │ ├── haml/ │ │ │ │ │ ├── haml.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── haskell/ │ │ │ │ │ ├── haskell.js │ │ │ │ │ └── index.html │ │ │ │ ├── haxe/ │ │ │ │ │ ├── haxe.js │ │ │ │ │ └── index.html │ │ │ │ ├── htmlembedded/ │ │ │ │ │ ├── htmlembedded.js │ │ │ │ │ └── index.html │ │ │ │ ├── htmlmixed/ │ │ │ │ │ ├── htmlmixed.js │ │ │ │ │ └── index.html │ │ │ │ ├── http/ │ │ │ │ │ ├── http.js │ │ │ │ │ └── index.html │ │ │ │ ├── index.html │ │ │ │ ├── jade/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── jade.js │ │ │ │ ├── javascript/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── javascript.js │ │ │ │ │ ├── test.js │ │ │ │ │ └── typescript.html │ │ │ │ ├── jinja2/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── jinja2.js │ │ │ │ ├── less/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── less.js │ │ │ │ ├── livescript/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── livescript.js │ │ │ │ │ └── livescript.ls │ │ │ │ ├── lua/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── lua.js │ │ │ │ ├── markdown/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── markdown.js │ │ │ │ │ └── test.js │ │ │ │ ├── meta.js │ │ │ │ ├── mirc/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── mirc.js │ │ │ │ ├── nginx/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── nginx.js │ │ │ │ ├── ntriples/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── ntriples.js │ │ │ │ ├── ocaml/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── ocaml.js │ │ │ │ ├── octave/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── octave.js │ │ │ │ ├── pascal/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── pascal.js │ │ │ │ ├── perl/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── perl.js │ │ │ │ ├── php/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── php.js │ │ │ │ ├── pig/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── pig.js │ │ │ │ ├── properties/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── properties.js │ │ │ │ ├── python/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── python.js │ │ │ │ ├── q/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── q.js │ │ │ │ ├── r/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── r.js │ │ │ │ ├── rpm/ │ │ │ │ │ ├── changes/ │ │ │ │ │ │ ├── changes.js │ │ │ │ │ │ └── index.html │ │ │ │ │ └── spec/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── spec.css │ │ │ │ │ └── spec.js │ │ │ │ ├── rst/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── rst.js │ │ │ │ ├── ruby/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── ruby.js │ │ │ │ ├── rust/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── rust.js │ │ │ │ ├── sass/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── sass.js │ │ │ │ ├── scheme/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── scheme.js │ │ │ │ ├── shell/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── shell.js │ │ │ │ ├── sieve/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── sieve.js │ │ │ │ ├── smalltalk/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── smalltalk.js │ │ │ │ ├── smarty/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── smarty.js │ │ │ │ ├── smartymixed/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── smartymixed.js │ │ │ │ ├── sparql/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── sparql.js │ │ │ │ ├── sql/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── sql.js │ │ │ │ ├── stex/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── stex.js │ │ │ │ │ └── test.js │ │ │ │ ├── tcl/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── tcl.js │ │ │ │ ├── tiddlywiki/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── tiddlywiki.css │ │ │ │ │ └── tiddlywiki.js │ │ │ │ ├── tiki/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── tiki.css │ │ │ │ │ └── tiki.js │ │ │ │ ├── toml/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── toml.js │ │ │ │ ├── turtle/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── turtle.js │ │ │ │ ├── vb/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── vb.js │ │ │ │ ├── vbscript/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── vbscript.js │ │ │ │ ├── velocity/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── velocity.js │ │ │ │ ├── verilog/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── verilog.js │ │ │ │ ├── xml/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── xml.js │ │ │ │ ├── xquery/ │ │ │ │ │ ├── index.html │ │ │ │ │ ├── test.js │ │ │ │ │ └── xquery.js │ │ │ │ ├── yaml/ │ │ │ │ │ ├── index.html │ │ │ │ │ └── yaml.js │ │ │ │ └── z80/ │ │ │ │ ├── index.html │ │ │ │ └── z80.js │ │ │ ├── package.json │ │ │ ├── test/ │ │ │ │ ├── comment_test.js │ │ │ │ ├── doc_test.js │ │ │ │ ├── driver.js │ │ │ │ ├── emacs_test.js │ │ │ │ ├── index.html │ │ │ │ ├── lint/ │ │ │ │ │ ├── acorn.js │ │ │ │ │ ├── lint.js │ │ │ │ │ └── walk.js │ │ │ │ ├── mode_test.css │ │ │ │ ├── mode_test.js │ │ │ │ ├── phantom_driver.js │ │ │ │ ├── run.js │ │ │ │ ├── test.js │ │ │ │ └── vim_test.js │ │ │ └── theme/ │ │ │ ├── 3024-day.css │ │ │ ├── 3024-night.css │ │ │ ├── ambiance-mobile.css │ │ │ ├── ambiance.css │ │ │ ├── base16-dark.css │ │ │ ├── base16-light.css │ │ │ ├── blackboard.css │ │ │ ├── cobalt.css │ │ │ ├── eclipse.css │ │ │ ├── elegant.css │ │ │ ├── erlang-dark.css │ │ │ ├── lesser-dark.css │ │ │ ├── mbo.css │ │ │ ├── midnight.css │ │ │ ├── monokai.css │ │ │ ├── neat.css │ │ │ ├── night.css │ │ │ ├── paraiso-dark.css │ │ │ ├── paraiso-light.css │ │ │ ├── rubyblue.css │ │ │ ├── solarized.css │ │ │ ├── the-matrix.css │ │ │ ├── tomorrow-night-eighties.css │ │ │ ├── twilight.css │ │ │ ├── vibrant-ink.css │ │ │ ├── xq-dark.css │ │ │ └── xq-light.css │ │ ├── google-code-prettify/ │ │ │ ├── lang-apollo.js │ │ │ ├── lang-basic.js │ │ │ ├── lang-clj.js │ │ │ ├── lang-css.js │ │ │ ├── lang-dart.js │ │ │ ├── lang-erlang.js │ │ │ ├── lang-go.js │ │ │ ├── lang-hs.js │ │ │ ├── lang-lisp.js │ │ │ ├── lang-llvm.js │ │ │ ├── lang-lua.js │ │ │ ├── lang-matlab.js │ │ │ ├── lang-ml.js │ │ │ ├── lang-mumps.js │ │ │ ├── lang-n.js │ │ │ ├── lang-pascal.js │ │ │ ├── lang-proto.js │ │ │ ├── lang-r.js │ │ │ ├── lang-rd.js │ │ │ ├── lang-scala.js │ │ │ ├── lang-sql.js │ │ │ ├── lang-tcl.js │ │ │ ├── lang-tex.js │ │ │ ├── lang-vb.js │ │ │ ├── lang-vhdl.js │ │ │ ├── lang-wiki.js │ │ │ ├── lang-xq.js │ │ │ ├── lang-yaml.js │ │ │ ├── prettify.css │ │ │ ├── prettify.js │ │ │ └── run_prettify.js │ │ └── jquery-file-upload-8.9.0/ │ │ ├── .gitignore │ │ ├── CONTRIBUTING.md │ │ ├── README.md │ │ ├── angularjs.html │ │ ├── basic-plus.html │ │ ├── basic.html │ │ ├── blueimp-file-upload.jquery.json │ │ ├── bower.json │ │ ├── cors/ │ │ │ ├── postmessage.html │ │ │ └── result.html │ │ ├── css/ │ │ │ ├── demo-ie8.css │ │ │ ├── demo.css │ │ │ ├── jquery.fileupload-noscript.css │ │ │ ├── jquery.fileupload-ui-noscript.css │ │ │ ├── jquery.fileupload-ui.css │ │ │ ├── jquery.fileupload.css │ │ │ └── style.css │ │ ├── index.html │ │ ├── jquery-ui.html │ │ ├── js/ │ │ │ ├── app.js │ │ │ ├── cors/ │ │ │ │ ├── jquery.postmessage-transport.js │ │ │ │ └── jquery.xdr-transport.js │ │ │ ├── jquery.fileupload-angular.js │ │ │ ├── jquery.fileupload-audio.js │ │ │ ├── jquery.fileupload-image.js │ │ │ ├── jquery.fileupload-jquery-ui.js │ │ │ ├── jquery.fileupload-process.js │ │ │ ├── jquery.fileupload-ui.js │ │ │ ├── jquery.fileupload-validate.js │ │ │ ├── jquery.fileupload-video.js │ │ │ ├── jquery.fileupload.js │ │ │ ├── jquery.iframe-transport.js │ │ │ ├── main.js │ │ │ └── vendor/ │ │ │ └── jquery.ui.widget.js │ │ ├── package.json │ │ ├── server/ │ │ │ ├── gae-go/ │ │ │ │ ├── app/ │ │ │ │ │ └── main.go │ │ │ │ ├── app.yaml │ │ │ │ └── static/ │ │ │ │ └── robots.txt │ │ │ ├── gae-python/ │ │ │ │ ├── app.yaml │ │ │ │ ├── main.py │ │ │ │ └── static/ │ │ │ │ └── robots.txt │ │ │ ├── node/ │ │ │ │ ├── .gitignore │ │ │ │ ├── package.json │ │ │ │ ├── public/ │ │ │ │ │ └── files/ │ │ │ │ │ └── .gitignore │ │ │ │ ├── server.js │ │ │ │ └── tmp/ │ │ │ │ └── .gitignore │ │ │ └── php/ │ │ │ ├── UploadHandler.php │ │ │ ├── files/ │ │ │ │ ├── .gitignore │ │ │ │ └── .htaccess │ │ │ └── index.php │ │ └── test/ │ │ ├── index.html │ │ └── test.js │ ├── robots.txt │ └── sitemap.xml ├── readme.md ├── server.php ├── vagrant.pp └── vagrantfile ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ * text=auto ================================================ FILE: .gitignore ================================================ /bootstrap/compiled.php /vendor composer.phar .DS_Store Thumbs.db # OSX .DS_Store # Project specific .sass-cache /public/uploads # local settings /app/config/local # production settings /app/config/production # test site basic auth public/.htpasswd # vagrant .vagrant /node_modules/ /.idea/ composer.lock ================================================ FILE: app/LaraSnipp/Command/CommentsCommand.php ================================================ info("Getting comment counts..."); $key = Config::get("disqus.key"); $forum = Config::get("disqus.shortname"); $endpoint = Config::get("disqus.endpoint"); $snippets = Snippet::orderBy("updated_comments_at", "asc")->take(50)->get(); foreach ($snippets as $snippet) { $link = sprintf($endpoint, $key, $forum, "snippet-" . $snippet->slug); $session = curl_init($link); curl_setopt($session, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($session); curl_close($session); $data = json_decode($response); if ($data->code == 0) { $snippet->comments = $data->response->posts; $snippet->updated_comments_at = date("Y-m-d H:i:s"); $snippet->save(); $this->info($link); } } } /** * Get the console command arguments. * * @return array */ protected function getArguments() { return []; } /** * Get the console command options. * * @return array */ protected function getOptions() { return []; } } ================================================ FILE: app/LaraSnipp/Composer/LayoutMasterComposer.php ================================================ commands( "larasnipp.command.comments" ); } /** * Bootstrap the application * * @return void */ public function boot() { $app = $this->app; // $app->singleton('redis', function() // { // return Redis::connection(); // }); $this->_bootComposers(); } private function _bootComposers() { } public function provides() { return [ "larasnipp.command.comments" ]; } } ================================================ FILE: app/LaraSnipp/Mailer/Mailer.php ================================================ from(\Config::get('site.mail_from'), \Config::get('site.name')); $message->to($user->email, $user->full_name)->subject($subject); }); } } ================================================ FILE: app/LaraSnipp/Mailer/UserMailer.php ================================================ $user, 'activationUrl' => route('auth.getActivateAccount', array($user->slug, $user->activation_key)) ); $subject = 'Please activate your account'; $view = 'emails.auth.activate'; return $this->sendTo($user, $subject, $view, $data); } } ================================================ FILE: app/LaraSnipp/Observer/ObserverServiceProvider.php ================================================ author_id = Auth::user()->id; } } ================================================ FILE: app/LaraSnipp/Observer/User/UserObserver.php ================================================ userMailer = $userMailer; } /** * Assign a role to the user that's being created (member by default) * * @param $user */ public function creating($user) { // generate activation key for the user being created $user->activation_key = md5(uniqid(rand(), true)); // @TODO: use a Role repository $role = \Role::where('name', 'member')->first(); $user->role()->associate($role); } /** * When the user was created, send the activation email * * @param $user */ public function created($user) { $this->userMailer->sendActivationEmail($user); } } ================================================ FILE: app/LaraSnipp/Repo/EloquentBaseRepository.php ================================================ model = $model; } /** * Returns all records * * @return mixed */ public function all() { return $this->model->all(); } /** * Create a new model * * @param array Data to create a new object * @return boolean */ public function create(array $data) { $model = $this->model->create($data); if (!$model) { return false; } return true; } /** * Get single model by slug * * @param string slug * @return object object of model */ public function bySlug($slug) { return $this->model->whereSlug($slug)->first(); } /** * Updates the model with the provided input * * @param $model * @param array $input * @return mixed */ public function update($model, array $input) { $model->fill($input); return $model->save(); } } ================================================ FILE: app/LaraSnipp/Repo/RepoServiceProvider.php ================================================ app; $app->bind('LaraSnipp\Repo\Snippet\SnippetRepositoryInterface', function ($app) { return new EloquentSnippetRepository( new Snippet, $app->make('LaraSnipp\Repo\Tag\TagRepositoryInterface'), $app->make('LaraSnipp\Repo\User\UserRepositoryInterface') ); }); $app->bind('LaraSnipp\Repo\User\UserRepositoryInterface', function ($app) { return new EloquentUserRepository(new User); }); $app->bind('LaraSnipp\Repo\Tag\TagRepositoryInterface', function ($app) { return new EloquentTagRepository(new Tag); }); } } ================================================ FILE: app/LaraSnipp/Repo/Snippet/EloquentSnippetRepository.php ================================================ snippet = $snippet; $this->tag = $tag; $this->user = $user; } /** * Get paginated snippets * * @param int $perPage * @param boolean $all Show published or all * @param $q * @return StdClass Object with $items and $totalItems for pagination */ public function byPage($perPage = 30, $all = false, $q = null) { $query = $q ? $this->snippet->like('title', $q)->orderBy('created_at', 'desc')->with('Starred') : $this->snippet->orderBy('created_at', 'desc')->with('Starred'); if (!$all) { $query->where('approved', 1); } return $query->paginate($perPage); } /** * Get total snippets count * * @todo I hate that this is public for the decorators. * Perhaps interface it? * @param bool $all * @return int Total snippets */ protected function totalSnippets($all = false) { if (!$all) { return $this->snippet->where('approved', 1)->count(); } return $this->snippet->count(); } /** * Get snippets by their tag * * @param $slug * @param int $page * @param int $limit * @internal param \LaraSnipp\Repo\Snippet\URL $string slug of tag * @internal param Number $int of snippets per page * @return StdClass Object with $items and $totalItems for pagination */ public function byTag($slug, $page = 1, $limit = 10) { $tag = $this->tag->bySlug($slug); $result = new \StdClass; $result->page = $page; $result->limit = $limit; $result->totalItems = 0; $result->items = array(); $result->tag = ''; if (!$tag) { return $result; } $snippets = $tag->snippets() ->where('approved', 1) ->orderBy('created_at', 'desc') ->skip($limit * ($page - 1)) ->take($limit) ->get(); $result->totalItems = $this->totalByTag($slug); $result->items = $snippets->all(); // attach tag in the result object so we can use it when needed $result->tag = $tag; return $result; } /** * Get total snippets count per tag * * @todo I hate that this is public for the decorators * Perhaps interface it? * @param $slug * @internal param string $tag Tag slug * @return int Total snippets per tag */ protected function totalByTag($slug) { return $this->tag->bySlug($slug) ->snippets() ->where('approved', 1) ->count(); } /** * Get snippets ordered by their number of views/hits * * @param int|string $limit Number of maximum snippets to return * @return \Illuminate\Database\Eloquent\Collection */ public function getMostViewed($limit = 5) { $redis = App::make('redis'); $mostViewedSnippets = $redis->zRevRange('hits', 0, $limit, array('withscores' => true)); $snippetIds = array(); // if there are no recorded hits in redis // lets return a blank eloquent collection if (empty($mostViewedSnippets)) { return new \Illuminate\Database\Eloquent\Collection; } foreach ($mostViewedSnippets as $snippet) { array_push($snippetIds, $snippet[0]); } $ids = implode(',', $snippetIds); // get all snippets at once and ordered by the current order // of ids inside $snippetIds array // // NOTE: here is the format // // Raw SQL: // SELECT * FROM snippets WHERE id IN (1,2) ORDER BY FIELD(id,2,1); // // Eloquent + raw query // $snippets = static::whereIn('id', $snippetIds) // ->orderByRaw(DB::raw("FIELD(id, 2,1)")) // ->get(); $snippets = $this->snippet->whereIn('id', $snippetIds) ->orderByRaw(DB::raw("FIELD(id, $ids)")) ->take($limit) ->get(); return $snippets; } /** * Get snippets by their author * * @param string $slug Slug of author * @param int $page Page number * @param int $limit Number of snippets per page * @param bool $all * @return StdClass Object with $items and $totalItems for pagination */ public function byAuthor($slug, $page = 1, $limit = 10, $all = false) { $user = $this->user->bySlug($slug); $result = new \StdClass; $result->page = $page; $result->limit = $limit; $result->totalItems = 0; $result->items = array(); if (!$user) { return $result; } $query = $user->snippets() ->orderBy('created_at', 'desc') ->skip($limit * ($page - 1)) ->take($limit); if (!$all) { $query->where('approved', 1); } $snippets = $query->get(); $result->totalItems = $this->totalByAuthor($slug); $result->items = $snippets->all(); // attach user in the result object so we can use it when needed $result->user = $user; return $result; } /** * Get total snippets count per author * * @todo I hate that this is public for the decorators * Perhaps interface it? * @param string $slug Author slug * @return int Total snippets per author */ protected function totalByAuthor($slug) { return $this->user->bySlug($slug) ->snippets() ->where('approved', 1) ->count(); } /** * Create a snippet * * @param array $data Array of inputs * @return boolean */ public function create(array $data) { if ($snippet = $this->snippet->create($data)) { if (isset($data['tags'])) { $snippet->tags()->sync($data['tags']); } else { $snippet->tags()->detach(); } return true; } return false; } /** * Update a snippet * * @param Illuminate\Database\Eloquent\Model $snippet Snippet Model * @param array $input * @internal param array $data Array of inputs * @return boolean */ public function update($snippet, array $input) { $snippet->fill($input); if ($snippet->save()) { if (isset($input['tags'])) { $snippet->tags()->sync($input['tags']); } else { $snippet->tags()->detach(); } return true; } return false; } /** * Get snippets by their slug * * @param string $slug Slug of snippet * @param boolean $all Wether to include not yet approved snippets * @return Illuminate\Database\Eloquent\Model */ public function bySlug($slug, $all = false) { $query = $this->model->whereSlug($slug); if (!$all) { $query->where('approved', 1); } return $query->first(); } } ================================================ FILE: app/LaraSnipp/Repo/Snippet/SnippetRepositoryInterface.php ================================================ tag = $tag; } } ================================================ FILE: app/LaraSnipp/Repo/Tag/TagRepositoryInterface.php ================================================ user = $user; } /** * Get top snippets contributors * * @param int $limit Results per page * @return Illuminate\Database\Eloquent\Collection */ public function getTopSnippetContributors($limit = 5) { return $this->user->from('users AS u') ->join('snippets AS s', 'u.id', '=', 's.author_id', 'LEFT OUTER') ->where('u.active', '=', 1) ->where('s.approved', '=', 1) ->whereRaw('s.deleted_at IS NULL') ->groupBy('s.author_id') ->orderBy('snippets_count', 'DESC') ->take($limit) ->get(array('u.id', 'u.first_name', 'u.last_name', 'u.slug', DB::raw('count(s.author_id) AS snippets_count'))); } /** * Get paginated users * * @param int $page Number of snippet per page * @param int $limit Results per page * @param boolean $all Show only active users or all * @return StdClass Object with $items and $totalItems for pagination */ public function byPage($page = 1, $limit = 10, $all = false) { $result = new \StdClass; $result->page = $page; $result->limit = $limit; $result->totalItems = 0; $result->items = array(); $query = $this->user->orderBy('created_at', 'desc'); if (! $all) { $query->where('active', 1); } $users = $query->skip($limit * ($page-1)) ->take($limit) ->get(); $result->totalItems = $this->totalUsers($all); $result->items = $users->all(); return $result; } /** * Get total users count * * @todo I hate that this is public for the decorators. * Perhaps interface it? * @param bool $all * @return int Total users */ protected function totalUsers($all = false) { if (! $all) { return $this->user->where('active', 1)->count(); } return $this->user->count(); } } ================================================ FILE: app/LaraSnipp/Repo/User/UserRepositoryInterface.php ================================================ app; $app->bind('LaraSnipp\Service\Form\User\UserForm', function ($app) { return new UserForm( new UserFormLaravelValidator($app['validator']), $app->make('LaraSnipp\Repo\User\UserRepositoryInterface') ); }); $app->bind('LaraSnipp\Service\Form\Snippet\SnippetForm', function ($app) { return new SnippetForm( new SnippetFormLaravelValidator($app['validator']), $app->make('LaraSnipp\Repo\Snippet\SnippetRepositoryInterface'), $app->make('LaraSnipp\Repo\Tag\TagRepositoryInterface') ); }); } } ================================================ FILE: app/LaraSnipp/Service/Form/Snippet/SnippetForm.php ================================================ validator = $validator; $this->snippet = $snippet; $this->tag = $tag; } /** * Create a new snippet * * @param array $input * @return boolean */ public function create(array $input) { if (!$this->valid($input, 'creating')) { return false; } // validate if tags chosen are valid // @TODO: move this into a helper so we can re-use this one $tagIds = $this->tag->all()->lists('id'); if (isset($input['tags']) && count($input['tags']) > 0) { foreach ($input['tags'] as $id) { if (!in_array($id, $tagIds)) { return App::abort(404); } } } return $this->snippet->create($input); } /** * Update the snippet * * @param $slug * @param array $input * @return bool|\LaraSnipp\Repo\Snippet\Illuminate\Database\Eloquent\Model */ public function update($slug, array $input) { $snippet = $this->snippet->bySlug($slug, $all = true); if (!$snippet->isTheAuthor(Auth::user())) { return App::abort(404); } if (!$this->valid($input, 'updating')) { return false; } // validate if tags chosen are valid // @TODO: move this into a helper so we can re-use this one $tagIds = $this->tag->all()->lists('id'); if (isset($input['tags']) && count($input['tags']) > 0) { foreach ($input['tags'] as $id) { if (!in_array($id, $tagIds)) { return App::abort(404); } } } if (!$this->snippet->update($snippet, $input)) return false; return $snippet; } /** * Return any validation errors * * @return array */ public function errors() { return $this->validator->errors(); } /** * Test if form validator passes * * @param array $input * @return boolean */ protected function valid(array $input, $mode) { return $this->validator->with($input)->passes($mode); } } ================================================ FILE: app/LaraSnipp/Service/Form/Snippet/SnippetFormLaravelValidator.php ================================================ [ 'title' => 'required', 'body' => 'required', 'resource' => 'url' ], 'updating' => [ 'title' => 'required', 'body' => 'required', 'resource' => 'url' ] ]; } ================================================ FILE: app/LaraSnipp/Service/Form/User/UserForm.php ================================================ validator = $validator; $this->user = $user; } /** * Create a new user * * @param array $input * @return boolean */ public function create(array $input) { if (!$this->valid($input, 'creating')) { return false; } return $this->user->create($input); } /** * Updates an existent user * * @param $user * @param array $input * @return bool */ public function update($user, array $input) { if (!$this->valid($input, 'updating')) { return false; } return $this->user->update($user, $input); } /** * Return any validation errors * * @return array */ public function errors() { return $this->validator->errors(); } /** * Test if form validator passes * * @param array $input * @param $mode : creating || updating * @return bool */ protected function valid(array $input, $mode) { return $this->validator->with($input)->passes($mode); } } ================================================ FILE: app/LaraSnipp/Service/Form/User/UserFormLaravelValidator.php ================================================ [ 'username' => 'required|between:3,16|unique:users', 'password' => 'required|min:4|confirmed', 'password_confirmation' => 'required|min:4', 'email' => 'required|email|unique:users', 'first_name' => 'required', 'last_name' => 'required' ], 'updating' => [ 'password' => 'min:8|confirmed', 'password_confirmation' => 'min:8', 'first_name' => 'required', 'last_name' => 'required', 'twitter_url' => 'url', 'facebook_url' => 'url', 'github_url' => 'url', 'website_url' => 'url' ] ]; } ================================================ FILE: app/LaraSnipp/Service/Validation/AbstractLaravelValidator.php ================================================ value array * * @var Array */ protected $data = array(); /** * Validation errors * * @var Array */ protected $errors = array(); /** * Validation rules * * @var Array */ protected $rules = array(); public function __construct(Factory $validator) { $this->validator = $validator; } /** * Set data to validate * * @param array $data * @return \LaraSnipp\Service\Validation\AbstractLaravelValidator */ public function with(array $data) { $this->data = $data; return $this; } /** * Validation passes or fails * * @param string $mode * @return bool */ public function passes($mode = 'creating') { if ($mode === 'updating') { $validator = $this->validator->make($this->data, $this->rules['updating']); } else { $validator = $this->validator->make($this->data, $this->rules['creating']); } if ($validator->fails()) { $this->errors = $validator->messages(); return false; } return true; } /** * Return errors, if any * * @return array */ public function errors() { return $this->errors; } } ================================================ FILE: app/LaraSnipp/Service/Validation/ValidableInterface.php ================================================ false, /* |-------------------------------------------------------------------------- | Application URL |-------------------------------------------------------------------------- | | This URL is used by the console to properly generate URLs when using | the Artisan command line tool. You should set this to the root of | your application so that it is used when running Artisan tasks. | */ 'url' => 'http://localhost', /* |-------------------------------------------------------------------------- | Application Timezone |-------------------------------------------------------------------------- | | Here you may specify the default timezone for your application, which | will be used by the PHP date and date-time functions. We have gone | ahead and set this to a sensible default for you out of the box. | */ 'timezone' => 'UTC', /* |-------------------------------------------------------------------------- | Application Locale Configuration |-------------------------------------------------------------------------- | | The application locale determines the default locale that will be used | by the translation service provider. You are free to set this value | to any of the locales which will be supported by the application. | */ 'locale' => 'en', /* |-------------------------------------------------------------------------- | Encryption Key |-------------------------------------------------------------------------- | | This key is used by the Illuminate encrypter service and should be set | to a random, 32 character string, otherwise these encrypted strings | will not be safe. Please do this before deploying an application! | */ 'key' => 'YourSecretKey!!!', /* |-------------------------------------------------------------------------- | Autoloaded Service Providers |-------------------------------------------------------------------------- | | The service providers listed here will be automatically loaded on the | request to your application. Feel free to add your own services to | this array to grant expanded functionality to your applications. | */ 'providers' => array( 'Illuminate\Foundation\Providers\ArtisanServiceProvider', 'Illuminate\Auth\AuthServiceProvider', 'Illuminate\Cache\CacheServiceProvider', 'Illuminate\Foundation\Providers\CommandCreatorServiceProvider', 'Illuminate\Session\CommandsServiceProvider', 'Illuminate\Foundation\Providers\ComposerServiceProvider', 'Illuminate\Routing\ControllerServiceProvider', 'Illuminate\Cookie\CookieServiceProvider', 'Illuminate\Database\DatabaseServiceProvider', 'Illuminate\Encryption\EncryptionServiceProvider', 'Illuminate\Filesystem\FilesystemServiceProvider', 'Illuminate\Hashing\HashServiceProvider', 'Illuminate\Html\HtmlServiceProvider', 'Illuminate\Foundation\Providers\KeyGeneratorServiceProvider', 'Illuminate\Log\LogServiceProvider', 'Illuminate\Mail\MailServiceProvider', 'Illuminate\Foundation\Providers\MaintenanceServiceProvider', 'Illuminate\Database\MigrationServiceProvider', 'Illuminate\Foundation\Providers\OptimizeServiceProvider', 'Illuminate\Pagination\PaginationServiceProvider', 'Illuminate\Foundation\Providers\PublisherServiceProvider', 'Illuminate\Queue\QueueServiceProvider', 'Illuminate\Redis\RedisServiceProvider', 'Illuminate\Auth\Reminders\ReminderServiceProvider', 'Illuminate\Foundation\Providers\RouteListServiceProvider', 'Illuminate\Database\SeedServiceProvider', 'Illuminate\Foundation\Providers\ServerServiceProvider', 'Illuminate\Session\SessionServiceProvider', 'Illuminate\Foundation\Providers\TinkerServiceProvider', 'Illuminate\Translation\TranslationServiceProvider', 'Illuminate\Validation\ValidationServiceProvider', 'Illuminate\View\ViewServiceProvider', 'Illuminate\Workbench\WorkbenchServiceProvider', 'Illuminate\Remote\RemoteServiceProvider', // app specific 'LaraSnipp\Repo\RepoServiceProvider', 'LaraSnipp\Service\Form\FormServiceProvider', 'LaraSnipp\Observer\ObserverServiceProvider', 'LaraSnipp\LaraSnippServiceProvider', // 3rd party 'Cviebrock\EloquentSluggable\SluggableServiceProvider', 'Mews\Purifier\PurifierServiceProvider', 'Bugsnag\BugsnagLaravel\BugsnagLaravelServiceProvider' ), /* |-------------------------------------------------------------------------- | Service Provider Manifest |-------------------------------------------------------------------------- | | The service provider manifest is used by Laravel to lazy load service | providers which are not needed for each request, as well to keep a | list of all of the services. Here, you may set its storage spot. | */ 'manifest' => storage_path().'/meta', /* |-------------------------------------------------------------------------- | Class Aliases |-------------------------------------------------------------------------- | | This array of class aliases will be registered when this application | is started. However, feel free to register as many as you wish as | the aliases are "lazy" loaded so they don't hinder performance. | */ 'aliases' => array( 'App' => 'Illuminate\Support\Facades\App', 'Artisan' => 'Illuminate\Support\Facades\Artisan', 'Auth' => 'Illuminate\Support\Facades\Auth', 'Blade' => 'Illuminate\Support\Facades\Blade', 'Cache' => 'Illuminate\Support\Facades\Cache', 'ClassLoader' => 'Illuminate\Support\ClassLoader', 'Config' => 'Illuminate\Support\Facades\Config', 'Controller' => 'Illuminate\Routing\Controller', 'Cookie' => 'Illuminate\Support\Facades\Cookie', 'Crypt' => 'Illuminate\Support\Facades\Crypt', 'DB' => 'Illuminate\Support\Facades\DB', 'Eloquent' => 'Illuminate\Database\Eloquent\Model', 'Event' => 'Illuminate\Support\Facades\Event', 'File' => 'Illuminate\Support\Facades\File', 'Form' => 'Illuminate\Support\Facades\Form', 'Hash' => 'Illuminate\Support\Facades\Hash', 'HTML' => 'Illuminate\Support\Facades\HTML', 'Input' => 'Illuminate\Support\Facades\Input', 'Lang' => 'Illuminate\Support\Facades\Lang', 'Log' => 'Illuminate\Support\Facades\Log', 'Mail' => 'Illuminate\Support\Facades\Mail', 'Paginator' => 'Illuminate\Support\Facades\Paginator', 'Password' => 'Illuminate\Support\Facades\Password', 'Queue' => 'Illuminate\Support\Facades\Queue', 'Redirect' => 'Illuminate\Support\Facades\Redirect', 'Redis' => 'Illuminate\Support\Facades\Redis', 'Request' => 'Illuminate\Support\Facades\Request', 'Response' => 'Illuminate\Support\Facades\Response', 'Route' => 'Illuminate\Support\Facades\Route', 'Schema' => 'Illuminate\Support\Facades\Schema', 'Seeder' => 'Illuminate\Database\Seeder', 'Session' => 'Illuminate\Support\Facades\Session', 'Str' => 'Illuminate\Support\Str', 'URL' => 'Illuminate\Support\Facades\URL', 'Validator' => 'Illuminate\Support\Facades\Validator', 'View' => 'Illuminate\Support\Facades\View', 'SSH' => 'Illuminate\Support\Facades\SSH', // 3rd party 'Sluggable' => 'Cviebrock\EloquentSluggable\Facades\Sluggable', 'Purifier' => 'Mews\Purifier\Facades\Purifier', 'Bugsnag' => 'Bugsnag\BugsnagLaravel\BugsnagFacade' ), 'cipher' => MCRYPT_RIJNDAEL_256 ); ================================================ FILE: app/config/auth.php ================================================ 'eloquent', /* |-------------------------------------------------------------------------- | Authentication Model |-------------------------------------------------------------------------- | | When using the "Eloquent" authentication driver, we need to know which | Eloquent model should be used to retrieve your users. Of course, it | is often just the "User" model but you may use whatever you like. | */ 'model' => 'User', /* |-------------------------------------------------------------------------- | Authentication Table |-------------------------------------------------------------------------- | | When using the "Database" authentication driver, we need to know which | table should be used to retrieve your users. We have chosen a basic | default value but you may easily change it to any table you like. | */ 'table' => 'users', /* |-------------------------------------------------------------------------- | Password Reminder Settings |-------------------------------------------------------------------------- | | Here you may set the settings for password reminders, including a view | that should be used as your password reminder e-mail. You will also | be able to set the name of the table that holds the reset tokens. | | The "expire" time is the number of minutes that the reminder should be | considered valid. This security feature keeps tokens short-lived so | they have less time to be guessed. You may change this as needed. | */ 'reminder' => array( 'email' => 'emails.auth.reminder', 'table' => 'password_reminders', 'expire' => 60, ), ); ================================================ FILE: app/config/cache.php ================================================ 'file', /* |-------------------------------------------------------------------------- | File Cache Location |-------------------------------------------------------------------------- | | When using the "file" cache driver, we need a location where the cache | files may be stored. A sensible default has been specified, but you | are free to change it to any other place on disk that you desire. | */ 'path' => storage_path().'/cache', /* |-------------------------------------------------------------------------- | Database Cache Connection |-------------------------------------------------------------------------- | | When using the "database" cache driver you may specify the connection | that should be used to store the cached items. When this option is | null the default database connection will be utilized for cache. | */ 'connection' => null, /* |-------------------------------------------------------------------------- | Database Cache Table |-------------------------------------------------------------------------- | | When using the "database" cache driver we need to know the table that | should be used to store the cached items. A default table name has | been provided but you're free to change it however you deem fit. | */ 'table' => 'cache', /* |-------------------------------------------------------------------------- | Memcached Servers |-------------------------------------------------------------------------- | | Now you may specify an array of your Memcached servers that should be | used when utilizing the Memcached cache driver. All of the servers | should contain a value for "host", "port", and "weight" options. | */ 'memcached' => array( array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100), ), /* |-------------------------------------------------------------------------- | Cache Key Prefix |-------------------------------------------------------------------------- | | When utilizing a RAM based store such as APC or Memcached, there might | be other applications utilizing the same cache. So, we'll specify a | value to get prefixed to all our keys so we can avoid collisions. | */ 'prefix' => 'laravel', ); ================================================ FILE: app/config/compile.php ================================================ PDO::FETCH_CLASS, /* |-------------------------------------------------------------------------- | Default Database Connection Name |-------------------------------------------------------------------------- | | Here you may specify which of the database connections below you wish | to use as your default connection for all database work. Of course | you may use many connections at once using the Database library. | */ 'default' => 'mysql', /* |-------------------------------------------------------------------------- | Database Connections |-------------------------------------------------------------------------- | | Here are each of the database connections setup for your application. | Of course, examples of configuring each database platform that is | supported by Laravel is shown below to make development simple. | | | All database work in Laravel is done through the PHP PDO facilities | so make sure you have the driver for your particular database of | choice installed on your machine before you begin development. | */ 'connections' => array( 'sqlite' => array( 'driver' => 'sqlite', 'database' => __DIR__.'/../database/production.sqlite', 'prefix' => '', ), 'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'database', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ), 'pgsql' => array( 'driver' => 'pgsql', 'host' => 'localhost', 'database' => 'database', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'prefix' => '', 'schema' => 'public', ), 'sqlsrv' => array( 'driver' => 'sqlsrv', 'host' => 'localhost', 'database' => 'database', 'username' => 'root', 'password' => '', 'prefix' => '', ), ), /* |-------------------------------------------------------------------------- | Migration Repository Table |-------------------------------------------------------------------------- | | This table keeps track of all the migrations that have already run for | your application. Using this information, we can determine which of | the migrations on disk have not actually be run in the databases. | */ 'migrations' => 'migrations', /* |-------------------------------------------------------------------------- | Redis Databases |-------------------------------------------------------------------------- | | Redis is an open source, fast, and advanced key-value store that also | provides a richer set of commands than a typical key-value systems | such as APC or Memcached. Laravel makes it easy to dig right in. | */ 'redis' => array( 'cluster' => false, 'default' => array( 'host' => '127.0.0.1', 'port' => 6379, 'database' => 0, ), ), ); ================================================ FILE: app/config/disqus.php ================================================ null, "shortname" => null, "endpoint" => "http://disqus.com/api/3.0/threads/details.json?api_key=%s&forum=%s&thread:ident=%s" ]; ================================================ FILE: app/config/mail.php ================================================ 'smtp', /* |-------------------------------------------------------------------------- | SMTP Host Address |-------------------------------------------------------------------------- | | Here you may provide the host address of the SMTP server used by your | applications. A default option is provided that is compatible with | the Postmark mail service, which will provide reliable delivery. | */ 'host' => 'smtp.mailgun.org', /* |-------------------------------------------------------------------------- | SMTP Host Port |-------------------------------------------------------------------------- | | This is the SMTP port used by your application to delivery e-mails to | users of your application. Like the host we have set this value to | stay compatible with the Postmark e-mail application by default. | */ 'port' => 587, /* |-------------------------------------------------------------------------- | Global "From" Address |-------------------------------------------------------------------------- | | You may wish for all e-mails sent by your application to be sent from | the same address. Here, you may specify a name and address that is | used globally for all e-mails that are sent by your application. | */ 'from' => array('address' => null, 'name' => null), /* |-------------------------------------------------------------------------- | E-Mail Encryption Protocol |-------------------------------------------------------------------------- | | Here you may specify the encryption protocol that should be used when | the application send e-mail messages. A sensible default using the | transport layer security protocol should provide great security. | */ 'encryption' => 'tls', /* |-------------------------------------------------------------------------- | SMTP Server Username |-------------------------------------------------------------------------- | | If your SMTP server requires a username for authentication, you should | set it here. This will get used to authenticate with your server on | connection. You may also set the "password" value below this one. | */ 'username' => null, /* |-------------------------------------------------------------------------- | SMTP Server Password |-------------------------------------------------------------------------- | | Here you may set the password required by your SMTP server to send out | messages from your application. This will be given to the server on | connection so that the application will be able to send messages. | */ 'password' => null, /* |-------------------------------------------------------------------------- | Sendmail System Path |-------------------------------------------------------------------------- | | When using the "sendmail" driver to send e-mails, we will need to know | the path to where Sendmail lives on this server. A default path has | been provided here, which will work well on most of your systems. | */ 'sendmail' => '/usr/sbin/sendmail -bs', /* |-------------------------------------------------------------------------- | Mail "Pretend" |-------------------------------------------------------------------------- | | When this option is enabled, e-mail will not actually be sent over the | web and will instead be written to your application's logs files so | you may inspect the message. This is great for local development. | */ 'pretend' => false, ); ================================================ FILE: app/config/packages/.gitkeep ================================================ ================================================ FILE: app/config/purifier.php ================================================ 'UTF-8', 'finalize' => true, 'preload' => false, 'settings' => array( 'default' => array( 'HTML.Doctype' => 'XHTML 1.0 Strict', 'HTML.Allowed' => 'code,div,b,strong,i,em,a[href|title],ul,ol,li,p[style],br,span[style],img[width|height|alt|src]', 'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align', 'AutoFormat.AutoParagraph' => true, 'AutoFormat.RemoveEmpty' => true, ), ), ); ================================================ FILE: app/config/queue.php ================================================ 'sync', /* |-------------------------------------------------------------------------- | Queue Connections |-------------------------------------------------------------------------- | | Here you may configure the connection information for each server that | is used by your application. A default configuration has been added | for each back-end shipped with Laravel. You are free to add more. | */ 'connections' => array( 'sync' => array( 'driver' => 'sync', ), 'beanstalkd' => array( 'driver' => 'beanstalkd', 'host' => 'localhost', 'queue' => 'default', ), 'sqs' => array( 'driver' => 'sqs', 'key' => 'your-public-key', 'secret' => 'your-secret-key', 'queue' => 'your-queue-url', 'region' => 'us-east-1', ), 'iron' => array( 'driver' => 'iron', 'project' => 'your-project-id', 'token' => 'your-token', 'queue' => 'your-queue-name', ), 'redis' => array( 'driver' => 'redis', 'queue' => 'default', ), ), /* |-------------------------------------------------------------------------- | Failed Queue Jobs |-------------------------------------------------------------------------- | | These options configure the behavior of failed queue job logging so you | can control which database and table are used to store the jobs that | have failed. You may change them to any database / table you wish. | */ 'failed' => array( 'database' => 'mysql', 'table' => 'failed_jobs', ), ); ================================================ FILE: app/config/remote.php ================================================ 'production', /* |-------------------------------------------------------------------------- | Remote Server Connections |-------------------------------------------------------------------------- | | These are the servers that will be accessible via the SSH task runner | facilities of Laravel. This feature radically simplifies executing | tasks on your servers, such as deploying out these applications. | */ 'connections' => array( 'production' => array( 'host' => '', 'username' => '', 'password' => '', 'key' => '', 'keyphrase' => '', 'root' => '/var/www', ), ), /* |-------------------------------------------------------------------------- | Remote Server Groups |-------------------------------------------------------------------------- | | Here you may list connections under a single group name, which allows | you to easily access all of the servers at once using a short name | that is extremely easy to remember, such as "web" or "database". | */ 'groups' => array( 'web' => array('production') ), ); ================================================ FILE: app/config/session.php ================================================ 'file', /* |-------------------------------------------------------------------------- | Session Lifetime |-------------------------------------------------------------------------- | | Here you may specify the number of minutes that you wish the session | to be allowed to remain idle before it expires. If you want them | to immediately expire on the browser closing, set that option. | */ 'lifetime' => 120, 'expire_on_close' => false, /* |-------------------------------------------------------------------------- | Session File Location |-------------------------------------------------------------------------- | | When using the native session driver, we need a location where session | files may be stored. A default has been set for you but a different | location may be specified. This is only needed for file sessions. | */ 'files' => storage_path().'/sessions', /* |-------------------------------------------------------------------------- | Session Database Connection |-------------------------------------------------------------------------- | | When using the "database" or "redis" session drivers, you may specify a | connection that should be used to manage these sessions. This should | correspond to a connection in your database configuration options. | */ 'connection' => null, /* |-------------------------------------------------------------------------- | Session Database Table |-------------------------------------------------------------------------- | | When using the "database" session driver, you may specify the table we | should use to manage the sessions. Of course, a sensible default is | provided for you; however, you are free to change this as needed. | */ 'table' => 'sessions', /* |-------------------------------------------------------------------------- | Session Sweeping Lottery |-------------------------------------------------------------------------- | | Some session drivers must manually sweep their storage location to get | rid of old sessions from storage. Here are the chances that it will | happen on a given request. By default, the odds are 2 out of 100. | */ 'lottery' => array(2, 100), /* |-------------------------------------------------------------------------- | Session Cookie Name |-------------------------------------------------------------------------- | | Here you may change the name of the cookie used to identify a session | instance by ID. The name specified here will get used every time a | new session cookie is created by the framework for every driver. | */ 'cookie' => 'laravel_session', /* |-------------------------------------------------------------------------- | Session Cookie Path |-------------------------------------------------------------------------- | | The session cookie path determines the path for which the cookie will | be regarded as available. Typically, this will be the root path of | your application but you are free to change this when necessary. | */ 'path' => '/', /* |-------------------------------------------------------------------------- | Session Cookie Domain |-------------------------------------------------------------------------- | | Here you may change the domain of the cookie used to identify a session | in your application. This will determine which domains the cookie is | available to in your application. A sensible default has been set. | */ 'domain' => null, /* |-------------------------------------------------------------------------- | HTTPS Only Cookies |-------------------------------------------------------------------------- | | By setting this option to true, session cookies will only be sent back | to the server if the browser has a HTTPS connection. This will keep | the cookie from being sent to you if it can not be done securely. | */ 'secure' => false, ); ================================================ FILE: app/config/site.php ================================================ 'http://www.laravelsnippets.com', 'url_short' => 'laravelsnippets.com', /* |-------------------------------------------------------------------------- | Google Analytics Config |-------------------------------------------------------------------------- */ 'ga_code' => 'UA-45609720-1', /* |-------------------------------------------------------------------------- | Facebook Config |-------------------------------------------------------------------------- */ 'facebook_url' => 'https://www.facebook.com/LaravelSnippets', 'facebook_username' => 'laravelsnippets', /* |-------------------------------------------------------------------------- | Twitter Config |-------------------------------------------------------------------------- */ 'twitter_url' => 'https://twitter.com/laravelsnippets', 'twitter_username' => 'laravelsnippets', 'twitter_via' => 'LaravelSnippets #Laravel #snippet', /* |-------------------------------------------------------------------------- | Header Config |-------------------------------------------------------------------------- */ 'title' => 'LaravelSnippets.com', 'meta_description' => 'A repository of useful code snippets for Laravel framework', 'meta_author' => 'John Kevin M. Basco', /* |-------------------------------------------------------------------------- | Footer Config |-------------------------------------------------------------------------- */ 'footer_copyright' => '© laravelsnippets.com by John Kevin M. Basco | Mayon Volcano Software Ltd.', /* |-------------------------------------------------------------------------- | Misc Config |-------------------------------------------------------------------------- */ 'name' => 'Laravel Snippets', 'welcome_message' => '
A repository of useful code snippets for Laravel PHP framework. Submit, grab and share!
Source code of the site - Github link . We accept pull requests! =)
', 'repo_url' => '//github.com/basco-johnkevin/laravelsnippets', 'mail_from' => 'basco.johnkevin@gmail.com', 'snippetsPerPage' => 30 ); ================================================ FILE: app/config/testing/app.php ================================================ true, ); ================================================ FILE: app/config/testing/cache.php ================================================ 'array', ); ================================================ FILE: app/config/testing/database.php ================================================ 'mysql', /* |-------------------------------------------------------------------------- | Database Connections |-------------------------------------------------------------------------- | | Here are each of the database connections setup for your application. | Of course, examples of configuring each database platform that is | supported by Laravel is shown below to make development simple. | | | All database work in Laravel is done through the PHP PDO facilities | so make sure you have the driver for your particular database of | choice installed on your machine before you begin development. | */ 'connections' => array( 'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'test.larasnipp', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ), ), /* |-------------------------------------------------------------------------- | Redis Databases |-------------------------------------------------------------------------- | | Redis is an open source, fast, and advanced key-value store that also | provides a richer set of commands than a typical key-value systems | such as APC or Memcached. Laravel makes it easy to dig right in. | */ 'redis' => array( 'cluster' => false, 'default' => array( 'host' => '127.0.0.1', 'port' => 6379, 'database' => 5, ), ), ); ================================================ FILE: app/config/testing/mail.php ================================================ true, ); ================================================ FILE: app/config/testing/session.php ================================================ 'array', ); ================================================ FILE: app/config/view.php ================================================ array(__DIR__.'/../views'), /* |-------------------------------------------------------------------------- | Pagination View |-------------------------------------------------------------------------- | | This view will be used to render the pagination link output, and can | be easily customized here to show any view you like. A clean view | compatible with Twitter's Bootstrap is given to you by default. | */ // 'pagination' => 'pagination::bootstrap-3', 'pagination' => 'partials/pagination', ); ================================================ FILE: app/config/workbench.php ================================================ '', /* |-------------------------------------------------------------------------- | Workbench Author E-Mail Address |-------------------------------------------------------------------------- | | Like the option above, your e-mail address is used when generating new | workbench packages. The e-mail is placed in your composer.json file | automatically after the package is created by the workbench tool. | */ 'email' => '', ); ================================================ FILE: app/controllers/.gitkeep ================================================ ================================================ FILE: app/controllers/Admin/IndexController.php ================================================ user = $user; $this->userForm = $userForm; } /** * Show signup form * GET /signup */ public function getSignup() { return View::make('auth.signup'); } /** * Process signup form * POST /signup */ public function postSignup() { if ($this->userForm->create(Input::all())) { return Redirect::route('auth.getLogin') ->with('message', 'Successfully registered. Please check your email and activate your account.') ->with('messageType', "success"); } return Redirect::route('auth.getSignup') ->withInput() ->withErrors($this->userForm->errors()); } /** * Activate account * GET /auth/activate/{slug}/key/{activation_key} */ public function getActivateAccount($userSlug, $activationKey) { $user = $this->user->bySlug($userSlug); if ($user->isActive()) { return Redirect::route('home') ->with('message', 'This user account is already active.'); } if ($user->activate($activationKey)) { Auth::login($user); return Redirect::route('home') ->with('message', 'Your account is now activated.') ->with('messageType', "success"); } else { return Redirect::route('home') ->with('message', 'Invalid activation key.'); } } /** * Show login form * GET /login */ public function getLogin() { return View::make('auth.login'); } /** * Process login * POST /login */ public function postLogin() { $params = array( 'username' => Input::get('username'), 'password' => Input::get('password'), 'active' => 1 ); if (Auth::attempt($params)) { // if next is present, redirect to that url $next = Input::get('next'); if ($next) return Redirect::to($next); return Redirect::route('home'); } return Redirect::route('auth.getLogin') ->with('message', 'Wrong username or password') ->withInput(); } /** * Process logout * GET /logout */ public function getLogout() { Auth::logout(); return Redirect::route('auth.getLogin'); } } ================================================ FILE: app/controllers/BaseController.php ================================================ layout)) { $this->layout = View::make($this->layout); } } } ================================================ FILE: app/controllers/HomeController.php ================================================ snippet = $snippet; $this->user = $user; $this->tag = $tag; } /** * Show home page * GET / */ public function getIndex() { $perPage = Config::get('site.snippetsPerPage'); $snippets = $this->snippet->byPage($perPage); $topSnippetContributors = $this->user->getTopSnippetContributors(); $mostViewedSnippets = $this->snippet->getMostViewed(10); $tags = $this->tag->all(); return View::make('website.pages.index', compact('snippets', 'topSnippetContributors', 'mostViewedSnippets', 'tags')); } } ================================================ FILE: app/controllers/Member/SnippetController.php ================================================ snippet = $snippet; $this->user = $user; $this->tag = $tag; $this->snippetForm = $snippetForm; } /** * Show a single snippet of a user * GET /members/snippets/{slug} * * @param string $slug Slug of a snippet */ public function getShow($slug) { $snippet = $this->snippet->bySlug($slug, $all = true); if (!$snippet) { return App::abort(404); } $user = Auth::user(); $has_starred = !empty($user) ? $user->hasStarred($snippet->id) : false; $tags = $this->tag->all(); $topSnippetContributors = $this->user->getTopSnippetContributors(); return View::make('snippets.show', compact('snippet', 'has_starred', 'tags', 'topSnippetContributors')); } /** * Show the snippet create form * GET /members/submit/snippet */ public function getCreate() { $tags = $this->tag->all()->lists('name', 'id'); return View::make('member.snippets.create', compact('tags')); } /** * Process snippet submission * POST /members/submit/snippet */ public function postStore() { if ($this->snippetForm->create(Input::all())) { return Redirect::route('member.snippet.getCreate') ->with('message', "Your snippet is now submitted and waiting for admin's approval") ->with('messageType', "success"); } return Redirect::route('member.snippet.getCreate') ->withInput() ->withErrors($this->snippetForm->errors()); } /** * Show the snippet edit form * GET /members/snippets/{slug}/edit */ public function getEdit($slug) { $snippet = $this->snippet->bySlug($slug, $all = true); // validate that the user updating the snippet is the snippet author if (!$snippet->isTheAuthor(Auth::user())) return App::abort(404); $tags = $this->tag->all()->lists('name', 'id'); return View::make('member.snippets.edit', compact('snippet', 'tags')); } /** * Process edit snippet form * POST /members/snippets/{slug}/update */ public function postUpdate($slug) { if ($snippet = $this->snippetForm->update($slug, Input::all())) { return Redirect::route('member.snippet.getShow', $snippet->slug) ->with('message', 'Update successful') ->with('messageType', 'success'); } return Redirect::back() ->withInput() ->withErrors($this->snippetForm->errors()); } } ================================================ FILE: app/controllers/Member/UserController.php ================================================ snippet = $snippet; } /** * Show dashboard with snippets and starred snippets of the current logged-in user * GET /members/dashboard */ public function dashboard() { $page = Input::get('page', 1); // Candidate for config item $perPage = 10; $pagiData = $this->snippet->byAuthor(Auth::user()->slug, $page, $perPage, $all = true); $my_snippets = Paginator::make($pagiData->items, $pagiData->totalItems, $perPage); $user = Auth::user(); $starred_snippets = $user->starred()->with('Snippet')->get(); return View::make('member.users.dashboard', compact('my_snippets', 'starred_snippets')); } } ================================================ FILE: app/controllers/RemindersController.php ================================================ with('message', 'Your email is invalid'); case Password::REMINDER_SENT: return Redirect::route('password.remind')->with('message', 'The password reminder has been sent. Check your email')->with('messageType', "success"); } } /** * Display the password reset view for the given token. * * @param string $token * @return \Illuminate\Http\Response */ public function getReset($token = null) { if (is_null($token)) { App::abort(404); } return View::make('password.reset')->with('token', $token); } /** * Handle a POST request to reset a user's password. * * @return \Illuminate\Http\Response */ public function postReset() { $credentials = Input::only( 'email', 'password', 'password_confirmation', 'token' ); $response = Password::reset($credentials, function ($user, $password) { $user->password = $password; $user->save(); }); switch ($response) { case Password::INVALID_PASSWORD: case Password::INVALID_TOKEN: return Redirect::route('password.remind')->with('message', "Your password remind request has expired or is invalid. Please request another one.") ->with('messageType', "warning"); case Password::INVALID_USER: return Redirect::route('password.reset')->with('message', "Whoops something went terribily wrong! Please retry") ->with('messageType', "danger"); case Password::PASSWORD_RESET: return Redirect::route('auth.getLogin')->with('message', 'Password successfully updated. Now log in')->with('messageType', 'success'); } } } ================================================ FILE: app/controllers/SnippetController.php ================================================ snippet = $snippet; $this->user = $user; $this->tag = $tag; } /** * Show listing of snippets * GET /snippets */ public function getIndex() { $perPage = Config::get('site.snippetsPerPage'); if (Request::has('q') and Request::get('q') !== '') $snippets = $this->snippet->byPage($perPage, false, e(Request::get('q'))); else $snippets = $this->snippet->byPage($perPage); $tags = $this->tag->all(); $topSnippetContributors = $this->user->getTopSnippetContributors(); return View::make('snippets.index', compact('snippets', 'tags', 'topSnippetContributors')); } /** * Show an individual snippet * GET /snippets/{slug} * @param $slug * @return */ public function getShow($slug) { $snippet = $this->snippet->bySlug($slug); if (!$snippet) { return App::abort(404); } $user = Auth::user(); $has_starred = !empty($user) ? $user->hasStarred($snippet->id) : false; # check cookie readlist $cookieName = md5('snippet.readlist'); $cookieJson = Cookie::get($cookieName); $cookieArray = json_decode($cookieJson); if (is_null($cookieArray) or !in_array($snippet->id, $cookieArray)) { # increment hit count if snippet id not exist cookie $snippet->incrementHits(); # put cookie the snippet id $cookieArray[] = $snippet->id; # attached all cookies for one week. Cookie::queue($cookieName, json_encode($cookieArray), 10080); } $tags = $this->tag->all(); $topSnippetContributors = $this->user->getTopSnippetContributors(); return View::make('snippets.show', compact('snippet', 'has_starred', 'tags', 'topSnippetContributors')); } /** * Stars a snippet * GET /snippets/{slug}/star * @param $slug * @return */ public function starSnippet($slug) { $snippet = $this->snippet->bySlug($slug); $user = Auth::user(); if (empty($user)) { return Redirect::route('snippet.getShow', array($slug)) ->with( 'message', sprintf( 'Only logged in users can star snippets. Please %s or %s.', link_to_route('auth.getLogin', 'login'), link_to_route('auth.getSignup', 'signup') ) ); } $user->starSnippet($snippet->id); return Redirect::route('snippet.getShow', array($slug)); } /** * Unstars a snippet * GET /snippets/{slug}/unstar * @param $slug * @return */ public function unstarSnippet($slug) { $snippet = $this->snippet->bySlug($slug); $user = Auth::user(); if (empty($user)) { return Redirect::route('snippet.getShow', array($slug)) ->with( 'message', sprintf( 'Only logged in users can unstar snippets. Please %s or %s.', link_to_route('auth.getLogin', 'login'), link_to_route('auth.getSignup', 'signup') ) ); } $user->unStarSnippet($snippet->id); return Redirect::route('snippet.getShow', array($slug)); } } ================================================ FILE: app/controllers/TagController.php ================================================ tag = $tag; $this->snippet = $snippet; $this->user = $user; } /** * Show listing of snippets filtered by a tag * GET /tags/{slug} */ public function getShow($slug) { $page = Input::get('page', 1); // Candidate for config item $perPage = 30; $pagiData = $this->snippet->byTag($slug, $page, $perPage); if (!$pagiData->tag) { return App::abort(404); } $tag = $pagiData->tag; $snippets = Paginator::make($pagiData->items, $pagiData->totalItems, $perPage); $tags = $this->tag->all(); $topSnippetContributors = $this->user->getTopSnippetContributors(); return View::make('tags.snippets', compact('snippets', 'tag', 'tags', 'topSnippetContributors')); } } ================================================ FILE: app/controllers/UserController.php ================================================ user = $user; $this->snippet = $snippet; $this->userForm = $userForm; } /** * Show listing of users * GET /profiles */ public function getIndex() { $page = Input::get('page', 1); // Candidate for config item $perPage = 12; $pagiData = $this->user->byPage($page, $perPage); $users = Paginator::make($pagiData->items, $pagiData->totalItems, $perPage); return View::make('users.index', compact('users')); } /** * Show profile of a user * GET /profiles/{slug} */ public function getProfile($slug) { $user = $this->user->bySlug($slug); if (!$user) { return App::abort(404); } return View::make('users.profile', compact('user')); } /** * Show listing of snippets of a user * GET /profiles/{slug}/snippets * @param $slug * @return */ public function getSnippets($slug) { $page = Input::get('page', 1); // Candidate for config item $perPage = 10; $pagiData = $this->snippet->byAuthor($slug, $page, $perPage); $user = $pagiData->user; $snippets = Paginator::make($pagiData->items, $pagiData->totalItems, $perPage); return View::make('users.snippets', compact('snippets', 'user')); } /** * Show user's settings page * GET /profiles/{slug}/settings * @param $slug */ public function getSettings($slug) { $user = Auth::user(); return View::make('users.settings', compact('user')); } /** * Updates user settings * @param $slug * @return mixed */ public function putSettings($slug) { $user = Auth::user(); $result = $this->userForm->update($user, Input::all()); if ($result) { return Redirect::route('user.getSettings', $slug) ->with('message', 'Successfully updated your settings.') ->with('messageType', "success"); } else { return Redirect::route('user.getSettings', $slug) ->withInput() ->withErrors($this->userForm->errors()); } } } ================================================ FILE: app/controllers/website/PagesController.php ================================================ increments('id'); $table->string('title'); $table->text('body'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('snippets'); } } ================================================ FILE: app/database/migrations/2013_12_05_122548_create_users_table.php ================================================ increments('id'); $table->string('username'); $table->string('email'); $table->string('password'); $table->string('first_name'); $table->string('last_name'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users'); } } ================================================ FILE: app/database/migrations/2013_12_05_122952_add_author_id_in_snippets_table.php ================================================ unsignedInteger('author_id'); $table->foreign('author_id')->references('id')->on('users'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('snippets', function ($table) { $table->dropForeign('snippets_author_id_foreign'); $table->dropColumn('author_id'); }); } } ================================================ FILE: app/database/migrations/2013_12_08_055430_add_slug_and_activation_key_and_active_in_users_table.php ================================================ string('slug'); $table->string('activation_key'); $table->string('active'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function ($table) { $table->dropColumn('slug'); $table->dropColumn('activation_key'); $table->dropColumn('active'); }); } } ================================================ FILE: app/database/migrations/2013_12_09_125456_drop_active_in_users_table.php ================================================ dropColumn('active'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function ($table) { $table->string('active'); }); } } ================================================ FILE: app/database/migrations/2013_12_09_130122_add_active_in_users_table.php ================================================ string('active')->default(0); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function ($table) { $table->dropColumn('active'); }); } } ================================================ FILE: app/database/migrations/2013_12_10_112312_add_approved_in_snippets_table.php ================================================ boolean('approved')->default(0); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('snippets', function ($table) { $table->dropColumn('approved'); }); } } ================================================ FILE: app/database/migrations/2013_12_10_132447_add_slug_in_snippets_table.php ================================================ string('slug')->default(0); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('snippets', function ($table) { $table->dropColumn('slug'); }); } } ================================================ FILE: app/database/migrations/2013_12_11_012940_create_roles_table.php ================================================ increments('id'); $table->string('name'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('roles'); } } ================================================ FILE: app/database/migrations/2013_12_11_013036_add_role_id_in_users_table.php ================================================ unsignedInteger('role_id'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function ($table) { $table->dropColumn('role_id'); }); } } ================================================ FILE: app/database/migrations/2013_12_11_013559_add_description_credits_to_resource_deleted_at_in_snippets_table.php ================================================ text('description')->nullable(); $table->string('credits_to')->nullable(); $table->string('resource')->nullable(); $table->softDeletes(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('snippets', function ($table) { $table->dropColumn('description'); $table->dropColumn('credits_to'); $table->dropColumn('resource'); $table->dropColumn('deleted_at'); }); } } ================================================ FILE: app/database/migrations/2013_12_11_014226_create_tags_table.php ================================================ increments('id'); $table->string('name'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('tags'); } } ================================================ FILE: app/database/migrations/2013_12_11_014317_create_snippet_tag_table.php ================================================ increments('id'); $table->unsignedInteger('snippet_id'); $table->unsignedInteger('tag_id'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('snippet_tag'); } } ================================================ FILE: app/database/migrations/2013_12_11_103428_add_slug_in_tags_table.php ================================================ string('slug'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('tags', function ($table) { $table->dropColumn('slug'); }); } } ================================================ FILE: app/database/migrations/2013_12_12_093641_add_remaining_columns_in_users_table.php ================================================ string('twitter_url')->nullable(); $table->string('facebook_url')->nullable(); $table->string('github_url')->nullable(); $table->string('website_url')->nullable(); $table->string('photo_url')->nullable(); $table->text('about_me')->nullable(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function ($table) { $table->dropColumn('twitter_url'); $table->dropColumn('facebook_url'); $table->dropColumn('github_url'); $table->dropColumn('website_url'); $table->dropColumn('photo_url'); $table->dropColumn('about_me'); }); } } ================================================ FILE: app/database/migrations/2013_12_19_134131_create_password_reminders_table.php ================================================ string('email')->index(); $table->string('token')->index(); $table->timestamp('created_at'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('password_reminders'); } } ================================================ FILE: app/database/migrations/2014_01_04_072223_add_disqus_columns_to_snippets_table.php ================================================ timestamp("updated_comments_at"); $table->integer("comments"); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table("snippets", function ($table) { $table->dropColumn("updated_comments_at"); $table->dropColumn("comments"); }); } } ================================================ FILE: app/database/migrations/2014_01_06_212314_create_user_starred_table.php ================================================ increments('id'); $table->unsignedInteger('user_id'); $table->unsignedInteger('snippet_id'); $table->index('user_id'); $table->index('snippet_id'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('user_starred'); } } ================================================ FILE: app/database/migrations/2014_04_17_151653_add_remember_token_to_users_table.php ================================================ string('remember_token', 100)->nullable(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function(Blueprint $table) { $table->dropColumn('remember_token'); }); } } ================================================ FILE: app/database/seeds/.gitkeep ================================================ ================================================ FILE: app/database/seeds/DatabaseSeeder.php ================================================ call('RoleSeeder'); $this->call('TagSeeder'); } } ================================================ FILE: app/database/seeds/RoleSeeder.php ================================================ generate(); } } private function generate() { $roles = array( 'admin', 'member' ); foreach ($roles as $role) { Role::create(array( 'name' => $role )); } } } ================================================ FILE: app/database/seeds/TagSeeder.php ================================================ generate(); } } private function generate() { $tags = array( 'auth' => 'auth', 'eloquent' => 'eloquent' ); foreach ($tags as $name => $slug) { Tag::create(array( 'name' => $name, 'slug' => $slug )); } } } ================================================ FILE: app/filters.php ================================================ $nextUrl))->with('message', $message); } return Redirect::route('auth.getLogin'); } }); Route::filter('admin', function ($route, $request) { if (!Auth::user()->isAdmin()) { return App::abort(401, 'You are not authorized.'); } }); Route::filter('auth.basic', function () { return Auth::basic(); }); /* |-------------------------------------------------------------------------- | Guest Filter |-------------------------------------------------------------------------- | | The "guest" filter is the counterpart of the authentication filters as | it simply checks that the current user is not logged in. A redirect | response will be issued if they are, which you may freely change. | */ Route::filter('guest', function () { if (Auth::check()) return Redirect::to('/'); }); /* |-------------------------------------------------------------------------- | CSRF Protection Filter |-------------------------------------------------------------------------- | | The CSRF filter is responsible for protecting your application against | cross-site request forgery attacks. If this special token in a user | session does not match the one given in this request, we'll bail. | */ Route::filter('csrf', function () { if (Session::token() != Input::get('_token')) { throw new Illuminate\Session\TokenMismatchException; } }); ================================================ FILE: app/lang/en/pagination.php ================================================ '« Previous', 'next' => 'Next »', ); ================================================ FILE: app/lang/en/reminders.php ================================================ "Passwords must be at least six characters and match the confirmation.", "user" => "We can't find a user with that e-mail address.", "token" => "This password reset token is invalid.", "sent" => "Password reminder sent!", ); ================================================ FILE: app/lang/en/validation.php ================================================ "The :attribute must be accepted.", "active_url" => "The :attribute is not a valid URL.", "after" => "The :attribute must be a date after :date.", "alpha" => "The :attribute may only contain letters.", "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.", "alpha_num" => "The :attribute may only contain letters and numbers.", "array" => "The :attribute must be an array.", "before" => "The :attribute must be a date before :date.", "between" => array( "numeric" => "The :attribute must be between :min and :max.", "file" => "The :attribute must be between :min and :max kilobytes.", "string" => "The :attribute must be between :min and :max characters.", "array" => "The :attribute must have between :min and :max items.", ), "confirmed" => "The :attribute confirmation does not match.", "date" => "The :attribute is not a valid date.", "date_format" => "The :attribute does not match the format :format.", "different" => "The :attribute and :other must be different.", "digits" => "The :attribute must be :digits digits.", "digits_between" => "The :attribute must be between :min and :max digits.", "email" => "The :attribute format is invalid.", "exists" => "The selected :attribute is invalid.", "image" => "The :attribute must be an image.", "in" => "The selected :attribute is invalid.", "integer" => "The :attribute must be an integer.", "ip" => "The :attribute must be a valid IP address.", "max" => array( "numeric" => "The :attribute may not be greater than :max.", "file" => "The :attribute may not be greater than :max kilobytes.", "string" => "The :attribute may not be greater than :max characters.", "array" => "The :attribute may not have more than :max items.", ), "mimes" => "The :attribute must be a file of type: :values.", "min" => array( "numeric" => "The :attribute must be at least :min.", "file" => "The :attribute must be at least :min kilobytes.", "string" => "The :attribute must be at least :min characters.", "array" => "The :attribute must have at least :min items.", ), "not_in" => "The selected :attribute is invalid.", "numeric" => "The :attribute must be a number.", "regex" => "The :attribute format is invalid.", "required" => "The :attribute field is required.", "required_if" => "The :attribute field is required when :other is :value.", "required_with" => "The :attribute field is required when :values is present.", "required_without" => "The :attribute field is required when :values is not present.", "same" => "The :attribute and :other must match.", "size" => array( "numeric" => "The :attribute must be :size.", "file" => "The :attribute must be :size kilobytes.", "string" => "The :attribute must be :size characters.", "array" => "The :attribute must contain :size items.", ), "unique" => "The :attribute has already been taken.", "url" => "The :attribute format is invalid.", /* |-------------------------------------------------------------------------- | Custom Validation Language Lines |-------------------------------------------------------------------------- | | Here you may specify custom validation messages for attributes using the | convention "attribute.rule" to name the lines. This makes it quick to | specify a specific custom language line for a given attribute rule. | */ 'custom' => array(), /* |-------------------------------------------------------------------------- | Custom Validation Attributes |-------------------------------------------------------------------------- | | The following language lines are used to swap attribute place-holders | with something more reader friendly such as E-Mail Address instead | of "email". This simply helps us make messages a little cleaner. | */ 'attributes' => array(), ); ================================================ FILE: app/libraries/SiteHelpers.php ================================================ type); } return !empty($body_classes) ? implode(' ', $body_classes) : NULL; } /** * Returns breadcrumbs made up by URI segments * * @return string */ public static function breadcrumbs() { $breadcrumbs = []; $crumbs = Request::segments(); if (count($crumbs) < 2) { return; } $url = ""; end($crumbs); $last_key = key($crumbs); foreach ($crumbs as $key => $crumb) { $url .= '/' . $crumb; $crumb = ucwords($crumb); if ($key != $last_key) { $crumb = '' . link_to($url, $crumb, ['rel' => 'v:url', 'property' => 'v:title']) . ''; } else if (Request::segment(1) === 'snippets') { $crumb = ""; } else { $crumb = '' . $crumb . ''; } array_push($breadcrumbs, $crumb); } $return = 'We encountered the following errors:
{{ HTML::submit('Sign in', array('class' => 'btn btn-lg btn-primary btn-block')) }}
@if ( isset( $next ) ) {{ Form::hidden('next', $value = 'snippets/create') }} @endif {{ Form::close() }}We encountered the following errors:
{{ HTML::submit('Register', array('class' => 'btn btn-lg btn-primary btn-block')) }}
{{ Form::close() }}We encountered the following errors:
GitHub-flavoured Markdown is supported.
We encountered the following errors:
GitHub-flavoured Markdown is supported.
No starred snippets yet. Why not add one?
@endifNo snippets yet. Why not add one?
@endifWant to help with the site? We accept pull requests! Find us on Github
| Snippet | Posted | |||
|---|---|---|---|---|
| title); ?> | humanCreatedAt; ?> | hasHits() ? $snippet->hits : '0'; ?> | comments ? $snippet->comments : '0'; ?> | starred->count(); ?> |
No snippets available.
================================================ FILE: app/views/password/remind.blade.php ================================================ @extends('layouts.master') @section('content')We encountered the following errors:
{{ HTML::submit('RESET PASSWORD', array('class' => 'btn-lg btn-primary btn-block')) }}
{{ Form::close() }}We encountered the following errors:
{{ Purifier::clean( Parsedown::instance()->parse( $snippet->description ), array('HTML.Nofollow' => true) ) }}
Credits to: {{ e($snippet->credits_to) }}
@elseCredits to: {{ e($snippet->credits_to) }}
@endif @endif @if($snippet->resource)Resource: {{ e($snippet->resource) }}
@endif{{ e($snippet->body) }}
@if ( App::environment() === 'production' )
@endif
OK, you're right, you've found a placeholder page. Dull right?
Actually, this page is an addition to resolve GitHub issue Roadmap, because we have plans to do bigger and better with {{{ Config::get('site.name') }}}, in part to serve as an example app and also to provide the web with a home for useful Laravel code snippets to speed up your development and help you to improve your code. We'll update this page soon with super interesting insight (for geeks) to see where we're going with this site and also for you to get involved, if you're geek enough of course. ;)
If you'd like to get involved, check out the {{{ Config::get('site.name') }}} GitHub repo and feel free to improve and submit pull requests!
Chosen is a Prototype plugin that makes long, unwieldy select boxes much more user-friendly.
Downloads Project Source Contribute
Looking for the jQuery version?
Chosen automatically highlights selected options and removes disabled options.
The disable_search_threshold option can be specified to hide the search input on single selects if there are fewer than (n) options.
new Chosen($("chosen_select_field"),{disable_search_threshold: 10});
Chosen automatically sets the default field text ("Choose a country...") by reading the select element's data-placeholder value. If no data-placeholder value is present, it will default to "Select an Option" or "Select Some Options" depending on whether the select is single or multiple. You can change these elements in the plugin js file as you see fit.
<select data-placeholder="Choose a country..." style="width:350px;" multiple class="chosen-select">
Note: on single selects, the first element is assumed to be selected by the browser. To take advantage of the default text support, you will need to include a blank option as the first element of your select list.
Setting the "No results" search text is as easy as passing an option when you create Chosen:
new Chosen($("chosen_select_field"),{no_results_text: "Oops, nothing found!"});
You can easily limit how many options the user can select:
new Chosen($("chosen_select_field"),{max_selected_options: 5});
If you try to select another option with limit reached chosen:maxselected event is triggered:
$("chosen_select_field").observe("chosen:maxselected", function(evt) { ... });
When a single select box isn't a required field, you can set allow_single_deselect: true and Chosen will add a UI element for option deselection. This will only work if the first option has blank text.
Chosen supports right to left select boxes too. just add "chosen-rtl" in addition to "chosen-select" to your select tags and you are good to go.
<select class="chosen-select chosen-rtl">
When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a "change" event* on the original form field. That let's you do something like this:
$("#form_field").chosen().change( … );
Note: Prototype doesn't offer support for triggering standard browser events. Event.simulate is required to trigger the change event when using the Prototype version.
If you need to update the options in your select field and want Chosen to pick up the changes, you'll need to trigger the "chosen:updated" event on the field. Chosen will re-build itself based on the updated content.
Event.fire($("form_field"), "chosen:updated");
Using a custom width with Chosen is as easy as passing an option when you create Chosen:
new Chosen($("chosen_select_field"),{width: "95%"});
Use labels just like you would a standard select
Using Chosen is easy as can be.
Yes! You can find them on the options page.
Yes! Please report all issues using the GitHub issue tracking tool. Please include the plugin version (jQuery or Prototype), browser and OS. The more information provided, the easier it is to fix a problem.
All modern browsers are supported (Firefox, Chrome, Safari and IE9). Legacy support for IE8 is also enabled.
Chosen has a number of options and attributes that allow you to have full control of your select boxes.
The following options are available to pass into Chosen on instantiation.
$(".my_select_box").chosen(
disable_search_threshold: 10,
no_results_text: "Oops, nothing found!",
width: "95%"
);
| Option | Default | Description |
|---|---|---|
| allow_single_deselect | false | When set to true on a single select, Chosen adds a UI element which selects the first elment (if it is blank). |
| disable_search | false | When set to true, Chosen will not display the search field (single selects only). |
| disable_search_threshold | 0 | Hide the search input on single selects if there are fewer than (n) options. |
| enable_split_word_search | true | By default, searching will match on any word within an option tag. Set this option to false if you want to only match on the entire text of an option tag. |
| inherit_select_classes | false | When set to true, Chosen will grab any classes on the original select field and add them to Chosen's container div. |
| max_selected_options | Infinity | Limits how many options the user can select. When the limit is reached, the chosen:maxselected event is triggered. |
| no_results_text | "No results match" | The text to be displayed when no matching results are found. The current search is shown at the end of the text (e.g. No reults match "Bad Search"). |
| placeholder_text_multiple | "Select Some Options" | The text to be displayed as a placeholder when no options are selected for a multiple select. | placeholder_text_single | "Select an Option" | The text to be displayed as a placeholder when no options are selected for a single select. |
| search_contains | false | By default, Chosen's search matches starting at the beginning of a word. Setting this option to true allows matches starting from anywhere within a word. This is especially useful for options that include a lot of special characters or phrases in ()'s and []'s. |
| single_backstroke_delete | true | By default, pressing delete/backspace on multiple selects will remove a selected choice. When false, pressing delete/backspace will highlight the last choice, and a second press deselects it. |
| width | Original select width. | The width of the Chosen select box. By default, Chosen attempts to match the width of the select box you are replacing. If your select is hidden when Chosen is instantiated, you must specify a width or the select will show up with a width of 0. |
| display_disabled_options | true | By default, Chosen includes disabled options in search results with a special styling. Setting this option to false will hide disabled results and exclude them from searches. |
| display_selected_options | true |
By default, Chosen includes selected options in search results with a special styling. Setting this option to false will hide selected results and exclude them from searches. Note: this is for multiple selects only. In single selects, the selected result will always be displayed. |
Certain attributes placed on the select tag or its options can be used to configure Chosen.
<select class="my_select_box" data-placeholder="Select Your Options">
<option value="1">Option 1</option>
<option value="2" selected>Option 2</option>
<option value="3" disabled>Option 3</option>
</select>
| Attribute | Description |
|---|---|
| data-placeholder |
The text to be displayed as a placeholder when no options are selected for a select. Defaults to "Select an Option" for single selects or "Select Some Options" for multiple selects.
Note:This attribute overrides anything set in the |
| multiple | The attribute multiple on your select box dictates whether Chosen will render a multiple or single select. |
| selected, disabled | Chosen automatically highlights selected options and disables disabled options. |
Classes placed on the select tag can be used to configure Chosen.
<select class="my_select_box chosen-rtl">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
| Classname | Description |
|---|---|
| chosen-rtl |
Chosen supports right-to-left text in select boxes. Add the class Note: The |
Chosen triggers a number of standard and custom events on the original select field.
$('select').on('change', function(evt, params) {
do_something(evt, params);
});
| Event | Description |
|---|---|
| change |
Chosen triggers the standard DOM event whenever a selection is made (it also sends a Note: in order to use change in the Prototype version, you have to include the Event.simulate class. The selected and deselected parameters are not available for Prototype. |
| chosen:ready | after Chosen has been fully instantiated (it also sends the chosen object as a parameter). |
| chosen:maxselected | triggered if max_selected_options is set and that total is broken. (it also sends the chosen object as a parameter) |
| chosen:showing_dropdown | triggered when Chosen's dropdown is opened (it also sends the chosen object as a parameter). |
| chosen:hiding_dropdown | triggered when Chosen's dropdown is closed (it also sends the chosen object as a parameter). |
Styling the current cursor line.
Press ctrl-space to activate autocompletion. The completion uses the anyword-hint.js module, which simply looks at nearby words in the buffer and completes to those.
Demonstration of bi-directional text support. See the related blog post for more background.
Note: There is a known bug with cursor motion and mouse clicks in bi-directional lines that are line wrapped.
Demonstration of
using linked documents
to provide a split view on a document, and
using swapDoc
to use a single editor to display multiple documents.
On changes to the content of the above editor, a (crude) script tries to auto-detect the language used, and switches the editor to either JavaScript or Scheme mode based on that.
Press ctrl-space to activate autocompletion. Built
on top of the show-hint
and javascript-hint
addons.
The emacs keybindings are enabled by
including keymap/emacs.js and setting
the keyMap option to "emacs". Because
CodeMirror's internal API is quite different from Emacs, they are only
a loose approximation of actual emacs bindings, though.
Also note that a lot of browsers disallow certain keys from being captured. For example, Chrome blocks both Ctrl-W and Ctrl-N, with the result that idiomatic use of Emacs keys will constantly close your tab or open a new window.
Demonstration of the fullscreen addon. Press F11 when cursor is in the editor to toggle full screen editing. Esc can also be used to exit full screen editing.
Demonstration of
the hardwrap addon.
The above editor has its change event hooked up to
the wrapParagraphsInRange method, so that the paragraphs
are reflown as you are typing.
Shows the XML completer parameterized with information about the tags in HTML. Press ctrl-space to activate completion.
This page uses a hack on top of the "renderLine"
event to make wrapped text line up with the base indentation of
the line.
Click the line-number gutter to add or remove 'breakpoints'.
Simple addon to easily mark (and style) selected text.
Search and highlight occurences of the selected text.
Put the cursor on or inside a pair of tags to highlight them. Press Ctrl-J to jump to the tag that matches the one under the cursor.
The merge
addon provides an interface for displaying and merging diffs,
either two-way
or three-way. The left
(or center) pane is editable, and the differences with the other
pane(s) are optionally shown live as you edit it.
This addon depends on the google-diff-match-patch library to compute the diffs.
Demonstration of a multiplexing mode, which, at certain
boundary strings, switches to one or more inner modes. The out
(HTML) mode does not get fed the content of the <<
>> blocks. See
the manual and
the source for more
information.
Demonstration of a mode that parses HTML, highlighting
the Mustache templating
directives inside of it by using the code
in overlay.js. View
source to see the 15 lines of code needed to accomplish this.
The placeholder
plug-in adds an option placeholder that can be set to
make text appear in the editor when it is empty and not focused.
If the source textarea has a placeholder attribute,
it will automatically be inherited.
By setting a few CSS properties, and giving
the viewportMargin
a value of Infinity, CodeMirror can be made to
automatically resize to fit its content.
Running a CodeMirror mode outside of the editor.
The CodeMirror.runMode function, defined
in lib/runmode.js takes the following arguments:
text (string)mode (mode spec)output (function or DOM node)null for unstyled tokens). If it is a DOM node,
the tokens will be converted to span elements as in
an editor, and inserted into the node
(through innerHTML).Demonstration of primitive search/replace functionality. The keybindings (which can be overridden by custom keymaps) are:
Searching is enabled by including addon/search/search.js and addon/search/searchcursor.js. For good-looking input dialogs, you also want to include addon/dialog/dialog.js and addon/dialog/dialog.css.
This is a hack to automatically derive
a spanAffectsWrapping regexp for a browser. See the
comments above that variable
in lib/codemirror.js
for some more details.
Select a theme:
Uses the trailingspace addon to highlight trailing whitespace.
The vim keybindings are enabled by
including keymap/vim.js and setting
the keyMap option to "vim". Because
CodeMirror's internal API is quite different from Vim, they are only
a loose approximation of actual vim bindings, though.
Tabs inside the editor are spans with the
class cm-tab, and can be styled.
This demo runs JSHint over the code in the editor (which is the script used on this page), and inserts line widgets to display the warnings that JSHint comes up with.
Press ctrl-space, or type a '<' character to activate autocompletion. This demo defines a simple schema that guides completion. The schema can be customized—see the manual.
Development of the xml-hint addon was kindly
sponsored
by www.xperiment.mobi.
To optimize loading CodeMirror, especially when including a bunch of different modes, it is recommended that you combine and minify (and preferably also gzip) the scripts. This page makes those first two steps very easy. Simply select the version and scripts you need in the form below, and click Compress to download the minified script file.
Topic: JavaScript, code editor implementation
Author: Marijn Haverbeke
Date: March 2nd 2011 (updated November 13th 2011)
Caution: this text was written briefly after version 2 was initially written. It no longer (even including the update at the bottom) fully represents the current implementation. I'm leaving it here as a historic document. For more up-to-date information, look at the entries tagged cm-internals on my blog.
This is a followup to my Brutal Odyssey to the Dark Side of the DOM Tree story. That one describes the mind-bending process of implementing (what would become) CodeMirror 1. This one describes the internals of CodeMirror 2, a complete rewrite and rethink of the old code base. I wanted to give this piece another Hunter Thompson copycat subtitle, but somehow that would be out of place—the process this time around was one of straightforward engineering, requiring no serious mind-bending whatsoever.
So, what is wrong with CodeMirror 1? I'd estimate, by mailing list activity and general search-engine presence, that it has been integrated into about a thousand systems by now. The most prominent one, since a few weeks, being Google code's project hosting. It works, and it's being used widely.
Still, I did not start replacing it because I was bored. CodeMirror
1 was heavily reliant on designMode
or contentEditable (depending on the browser). Neither of
these are well specified (HTML5 tries
to specify
their basics), and, more importantly, they tend to be one of the more
obscure and buggy areas of browser functionality—CodeMirror, by using
this functionality in a non-typical way, was constantly running up
against browser bugs. WebKit wouldn't show an empty line at the end of
the document, and in some releases would suddenly get unbearably slow.
Firefox would show the cursor in the wrong place. Internet Explorer
would insist on linkifying everything that looked like a URL or email
address, a behaviour that can't be turned off. Some bugs I managed to
work around (which was often a frustrating, painful process), others,
such as the Firefox cursor placement, I gave up on, and had to tell
user after user that they were known problems, but not something I
could help.
Also, there is the fact that designMode (which seemed
to be less buggy than contentEditable in Webkit and
Firefox, and was thus used by CodeMirror 1 in those browsers) requires
a frame. Frames are another tricky area. It takes some effort to
prevent getting tripped up by domain restrictions, they don't
initialize synchronously, behave strangely in response to the back
button, and, on several browsers, can't be moved around the DOM
without having them re-initialize. They did provide a very nice way to
namespace the library, though—CodeMirror 1 could freely pollute the
namespace inside the frame.
Finally, working with an editable document means working with
selection in arbitrary DOM structures. Internet Explorer (8 and
before) has an utterly different (and awkward) selection API than all
of the other browsers, and even among the different implementations of
document.selection, details about how exactly a selection
is represented vary quite a bit. Add to that the fact that Opera's
selection support tended to be very buggy until recently, and you can
imagine why CodeMirror 1 contains 700 lines of selection-handling
code.
And that brings us to the main issue with the CodeMirror 1 code base: The proportion of browser-bug-workarounds to real application code was getting dangerously high. By building on top of a few dodgy features, I put the system in a vulnerable position—any incompatibility and bugginess in these features, I had to paper over with my own code. Not only did I have to do some serious stunt-work to get it to work on older browsers (as detailed in the previous story), things also kept breaking in newly released versions, requiring me to come up with new scary hacks in order to keep up. This was starting to lose its appeal.
What CodeMirror 2 does is try to sidestep most of the hairy hacks that came up in version 1. I owe a lot to the ACE editor for inspiration on how to approach this.
I absolutely did not want to be completely reliant on key events to generate my input. Every JavaScript programmer knows that key event information is horrible and incomplete. Some people (most awesomely Mihai Bazon with Ymacs) have been able to build more or less functioning editors by directly reading key events, but it takes a lot of work (the kind of never-ending, fragile work I described earlier), and will never be able to properly support things like multi-keystoke international character input. [see below for caveat]
So what I do is focus a hidden textarea, and let the browser believe that the user is typing into that. What we show to the user is a DOM structure we built to represent his document. If this is updated quickly enough, and shows some kind of believable cursor, it feels like a real text-input control.
Another big win is that this DOM representation does not have to
span the whole document. Some CodeMirror 1 users insisted that they
needed to put a 30 thousand line XML document into CodeMirror. Putting
all that into the DOM takes a while, especially since, for some
reason, an editable DOM tree is slower than a normal one on most
browsers. If we have full control over what we show, we must only
ensure that the visible part of the document has been added, and can
do the rest only when needed. (Fortunately, the onscroll
event works almost the same on all browsers, and lends itself well to
displaying things only as they are scrolled into view.)
ACE uses its hidden textarea only as a text input shim, and does all cursor movement and things like text deletion itself by directly handling key events. CodeMirror's way is to let the browser do its thing as much as possible, and not, for example, define its own set of key bindings. One way to do this would have been to have the whole document inside the hidden textarea, and after each key event update the display DOM to reflect what's in that textarea.
That'd be simple, but it is not realistic. For even medium-sized document the editor would be constantly munging huge strings, and get terribly slow. What CodeMirror 2 does is put the current selection, along with an extra line on the top and on the bottom, into the textarea.
This means that the arrow keys (and their ctrl-variations), home, end, etcetera, do not have to be handled specially. We just read the cursor position in the textarea, and update our cursor to match it. Also, copy and paste work pretty much for free, and people get their native key bindings, without any special work on my part. For example, I have emacs key bindings configured for Chrome and Firefox. There is no way for a script to detect this. [no longer the case]
Of course, since only a small part of the document sits in the textarea, keys like page up and ctrl-end won't do the right thing. CodeMirror is catching those events and handling them itself.
Getting and setting the selection range of a textarea in modern
browsers is trivial—you just use the selectionStart
and selectionEnd properties. On IE you have to do some
insane stuff with temporary ranges and compensating for the fact that
moving the selection by a 'character' will treat \r\n as a single
character, but even there it is possible to build functions that
reliably set and get the selection range.
But consider this typical case: When I'm somewhere in my document, press shift, and press the up arrow, something gets selected. Then, if I, still holding shift, press the up arrow again, the top of my selection is adjusted. The selection remembers where its head and its anchor are, and moves the head when we shift-move. This is a generally accepted property of selections, and done right by every editing component built in the past twenty years.
But not something that the browser selection APIs expose.
Great. So when someone creates an 'upside-down' selection, the next time CodeMirror has to update the textarea, it'll re-create the selection as an 'upside-up' selection, with the anchor at the top, and the next cursor motion will behave in an unexpected way—our second up-arrow press in the example above will not do anything, since it is interpreted in exactly the same way as the first.
No problem. We'll just, ehm, detect that the selection is upside-down (you can tell by the way it was created), and then, when an upside-down selection is present, and a cursor-moving key is pressed in combination with shift, we quickly collapse the selection in the textarea to its start, allow the key to take effect, and then combine its new head with its old anchor to get the real selection.
In short, scary hacks could not be avoided entirely in CodeMirror 2.
And, the observant reader might ask, how do you even know that a key combo is a cursor-moving combo, if you claim you support any native key bindings? Well, we don't, but we can learn. The editor keeps a set known cursor-movement combos (initialized to the predictable defaults), and updates this set when it observes that pressing a certain key had (only) the effect of moving the cursor. This, of course, doesn't work if the first time the key is used was for extending an inverted selection, but it works most of the time.
One thing that always comes up when you have a complicated internal state that's reflected in some user-visible external representation (in this case, the displayed code and the textarea's content) is keeping the two in sync. The naive way is to just update the display every time you change your state, but this is not only error prone (you'll forget), it also easily leads to duplicate work on big, composite operations. Then you start passing around flags indicating whether the display should be updated in an attempt to be efficient again and, well, at that point you might as well give up completely.
I did go down that road, but then switched to a much simpler model: simply keep track of all the things that have been changed during an action, and then, only at the end, use this information to update the user-visible display.
CodeMirror uses a concept of operations, which start by
calling a specific set-up function that clears the state and end by
calling another function that reads this state and does the required
updating. Most event handlers, and all the user-visible methods that
change state are wrapped like this. There's a method
called operation that accepts a function, and returns
another function that wraps the given function as an operation.
It's trivial to extend this (as CodeMirror does) to detect nesting, and, when an operation is started inside an operation, simply increment the nesting count, and only do the updating when this count reaches zero again.
If we have a set of changed ranges and know the currently shown range, we can (with some awkward code to deal with the fact that changes can add and remove lines, so we're dealing with a changing coordinate system) construct a map of the ranges that were left intact. We can then compare this map with the part of the document that's currently visible (based on scroll offset and editor height) to determine whether something needs to be updated.
CodeMirror uses two update algorithms—a full refresh, where it just discards the whole part of the DOM that contains the edited text and rebuilds it, and a patch algorithm, where it uses the information about changed and intact ranges to update only the out-of-date parts of the DOM. When more than 30 percent (which is the current heuristic, might change) of the lines need to be updated, the full refresh is chosen (since it's faster to do than painstakingly finding and updating all the changed lines), in the other case it does the patching (so that, if you scroll a line or select another character, the whole screen doesn't have to be re-rendered). [the full-refresh algorithm was dropped, it wasn't really faster than the patching one]
All updating uses innerHTML rather than direct DOM
manipulation, since that still seems to be by far the fastest way to
build documents. There's a per-line function that combines the
highlighting, marking, and
selection info for that line into a snippet of HTML. The patch updater
uses this to reset individual lines, the refresh updater builds an
HTML chunk for the whole visible document at once, and then uses a
single innerHTML update to do the refresh.
When I wrote CodeMirror 1, I thought interruptable parsers were a hugely scary and complicated thing, and I used a bunch of heavyweight abstractions to keep this supposed complexity under control: parsers were iterators that consumed input from another iterator, and used funny closure-resetting tricks to copy and resume themselves.
This made for a rather nice system, in that parsers formed strictly separate modules, and could be composed in predictable ways. Unfortunately, it was quite slow (stacking three or four iterators on top of each other), and extremely intimidating to people not used to a functional programming style.
With a few small changes, however, we can keep all those advantages, but simplify the API and make the whole thing less indirect and inefficient. CodeMirror 2's mode API uses explicit state objects, and makes the parser/tokenizer a function that simply takes a state and a character stream abstraction, advances the stream one token, and returns the way the token should be styled. This state may be copied, optionally in a mode-defined way, in order to be able to continue a parse at a given point. Even someone who's never touched a lambda in his life can understand this approach. Additionally, far fewer objects are allocated in the course of parsing now.
The biggest speedup comes from the fact that the parsing no longer has to touch the DOM though. In CodeMirror 1, on an older browser, you could see the parser work its way through the document, managing some twenty lines in each 50-millisecond time slice it got. It was reading its input from the DOM, and updating the DOM as it went along, which any experienced JavaScript programmer will immediately spot as a recipe for slowness. In CodeMirror 2, the parser usually finishes the whole document in a single 100-millisecond time slice—it manages some 1500 lines during that time on Chrome. All it has to do is munge strings, so there is no real reason for it to be slow anymore.
Given all this, what can you expect from CodeMirror 2?
iframe nodes aren't
really known for respecting document flow. Now that an editor instance
is a plain div element, it is much easier to size it to
fit the surrounding elements. You don't even have to make it scroll if
you do not want to.On the downside, a CodeMirror 2 instance is not a native editable component. Though it does its best to emulate such a component as much as possible, there is functionality that browsers just do not allow us to hook into. Doing select-all from the context menu, for example, is not currently detected by CodeMirror.
[Updates from November 13th 2011] Recently, I've made some changes to the codebase that cause some of the text above to no longer be current. I've left the text intact, but added markers at the passages that are now inaccurate. The new situation is described below.
The original implementation of CodeMirror 2 represented the
document as a flat array of line objects. This worked well—splicing
arrays will require the part of the array after the splice to be
moved, but this is basically just a simple memmove of a
bunch of pointers, so it is cheap even for huge documents.
However, I recently added line wrapping and code folding (line collapsing, basically). Once lines start taking up a non-constant amount of vertical space, looking up a line by vertical position (which is needed when someone clicks the document, and to determine the visible part of the document during scrolling) can only be done with a linear scan through the whole array, summing up line heights as you go. Seeing how I've been going out of my way to make big documents fast, this is not acceptable.
The new representation is based on a B-tree. The leaves of the tree contain arrays of line objects, with a fixed minimum and maximum size, and the non-leaf nodes simply hold arrays of child nodes. Each node stores both the amount of lines that live below them and the vertical space taken up by these lines. This allows the tree to be indexed both by line number and by vertical position, and all access has logarithmic complexity in relation to the document size.
I gave line objects and tree nodes parent pointers, to the node above them. When a line has to update its height, it can simply walk these pointers to the top of the tree, adding or subtracting the difference in height from each node it encounters. The parent pointers also make it cheaper (in complexity terms, the difference is probably tiny in normal-sized documents) to find the current line number when given a line object. In the old approach, the whole document array had to be searched. Now, we can just walk up the tree and count the sizes of the nodes coming before us at each level.
I chose B-trees, not regular binary trees, mostly because they allow for very fast bulk insertions and deletions. When there is a big change to a document, it typically involves adding, deleting, or replacing a chunk of subsequent lines. In a regular balanced tree, all these inserts or deletes would have to be done separately, which could be really expensive. In a B-tree, to insert a chunk, you just walk down the tree once to find where it should go, insert them all in one shot, and then break up the node if needed. This breaking up might involve breaking up nodes further up, but only requires a single pass back up the tree. For deletion, I'm somewhat lax in keeping things balanced—I just collapse nodes into a leaf when their child count goes below a given number. This means that there are some weird editing patterns that may result in a seriously unbalanced tree, but even such an unbalanced tree will perform well, unless you spend a day making strangely repeating edits to a really big document.
Above, I claimed that directly catching key events for things like cursor movement is impractical because it requires some browser-specific kludges. I then proceeded to explain some awful hacks that were needed to make it possible for the selection changes to be detected through the textarea. In fact, the second hack is about as bad as the first.
On top of that, in the presence of user-configurable tab sizes and collapsed and wrapped lines, lining up cursor movement in the textarea with what's visible on the screen becomes a nightmare. Thus, I've decided to move to a model where the textarea's selection is no longer depended on.
So I moved to a model where all cursor movement is handled by my own code. This adds support for a goal column, proper interaction of cursor movement with collapsed lines, and makes it possible for vertical movement to move through wrapped lines properly, instead of just treating them like non-wrapped lines.
The key event handlers now translate the key event into a string,
something like Ctrl-Home or Shift-Cmd-R, and
use that string to look up an action to perform. To make keybinding
customizable, this lookup goes through
a table, using a scheme that
allows such tables to be chained together (for example, the default
Mac bindings fall through to a table named 'emacsy', which defines
basic Emacs-style bindings like Ctrl-F, and which is also
used by the custom Emacs bindings).
A new
option extraKeys
allows ad-hoc keybindings to be defined in a much nicer way than what
was possible with the
old onKeyEvent
callback. You simply provide an object mapping key identifiers to
functions, instead of painstakingly looking at raw key events.
Built-in commands map to strings, rather than functions, for
example "goLineUp" is the default action bound to the up
arrow key. This allows new keymaps to refer to them without
duplicating any code. New commands can be defined by assigning to
the CodeMirror.commands object, which maps such commands
to functions.
The hidden textarea now only holds the current selection, with no extra characters around it. This has a nice advantage: polling for input becomes much, much faster. If there's a big selection, this text does not have to be read from the textarea every time—when we poll, just noticing that something is still selected is enough to tell us that no new text was typed.
The reason that cheap polling is important is that many browsers do
not fire useful events on IME (input method engine) input, which is
the thing where people inputting a language like Japanese or Chinese
use multiple keystrokes to create a character or sequence of
characters. Most modern browsers fire input when the
composing is finished, but many don't fire anything when the character
is updated during composition. So we poll, whenever the
editor is focused, to provide immediate updates of the display.
CodeMirror is a code-editor component that can be embedded in Web pages. The core library provides only the editor component, no accompanying buttons, auto-completion, or other IDE functionality. It does provide a rich API on top of which such functionality can be straightforwardly implemented. See the addons included in the distribution, and the list of externally hosted addons, for reusable implementations of extra features.
CodeMirror works with language-specific modes. Modes are
JavaScript programs that help color (and optionally indent) text
written in a given language. The distribution comes with a number
of modes (see the mode/
directory), and it isn't hard to write new
ones for other languages.
The easiest way to use CodeMirror is to simply load the script
and style sheet found under lib/ in the distribution,
plus a mode script from one of the mode/ directories.
(See the compression helper for an
easy way to combine scripts.) For example:
<script src="lib/codemirror.js"></script> <link rel="stylesheet" href="../lib/codemirror.css"> <script src="mode/javascript/javascript.js"></script>
Having done this, an editor instance can be created like this:
var myCodeMirror = CodeMirror(document.body);
The editor will be appended to the document body, will start
empty, and will use the mode that we loaded. To have more control
over the new editor, a configuration object can be passed
to CodeMirror as a second
argument:
var myCodeMirror = CodeMirror(document.body, {
value: "function myScript(){return 100;}\n",
mode: "javascript"
});
This will initialize the editor with a piece of code already in it, and explicitly tell it to use the JavaScript mode (which is useful when multiple modes are loaded). See below for a full discussion of the configuration options that CodeMirror accepts.
In cases where you don't want to append the editor to an
element, and need more control over the way it is inserted, the
first argument to the CodeMirror function can also
be a function that, when given a DOM element, inserts it into the
document somewhere. This could be used to, for example, replace a
textarea with a real editor:
var myCodeMirror = CodeMirror(function(elt) {
myTextArea.parentNode.replaceChild(elt, myTextArea);
}, {value: myTextArea.value});
However, for this use case, which is a common way to use CodeMirror, the library provides a much more powerful shortcut:
var myCodeMirror = CodeMirror.fromTextArea(myTextArea);
This will, among other things, ensure that the textarea's value is updated with the editor's contents when the form (if it is part of a form) is submitted. See the API reference for a full description of this method.
Both the CodeMirror
function and its fromTextArea method take as second
(optional) argument an object containing configuration options.
Any option not supplied like this will be taken
from CodeMirror.defaults, an
object containing the default options. You can update this object
to change the defaults on your page.
Options are not checked in any way, so setting bogus option values is bound to lead to odd errors.
These are the supported options:
value: string|CodeMirror.Docmode: string|objectname property that names the mode (for
example {name: "javascript", json: true}). The demo
pages for each mode contain information about what configuration
parameters the mode supports. You can ask CodeMirror which modes
and MIME types have been defined by inspecting
the CodeMirror.modes
and CodeMirror.mimeModes objects. The first maps
mode names to their constructors, and the second maps MIME types
to mode specs.theme: string.cm-s-[name]
styles is loaded (see
the theme directory in the
distribution). The default is "default", for which
colors are included in codemirror.css. It is
possible to use multiple theming classes at once—for
example "foo bar" will assign both
the cm-s-foo and the cm-s-bar classes
to the editor.indentUnit: integersmartIndent: booleantabSize: integerindentWithTabs: booleantabSize
spaces should be replaced by N tabs. Default is false.electricChars: booleanrtlMoveVisually: booleanfalse
on Windows, and true on other platforms.keyMap: string"default", which is the only keymap defined
in codemirror.js itself. Extra keymaps are found in
the keymap directory. See
the section on keymaps for more
information.extraKeys: objectkeyMap. Should be
either null, or a valid keymap value.lineWrapping: booleanfalse (scroll).lineNumbers: booleanfirstLineNumber: integerlineNumberFormatter: function(line: integer) → stringgutters: array<string>width (and optionally a
background), and which will be used to draw the background of
the gutters. May include
the CodeMirror-linenumbers class, in order to
explicitly set the position of the line number gutter (it will
default to be to the right of all other gutters). These class
names are the keys passed
to setGutterMarker.fixedGutter: booleancoverGutterNextToScrollbar: booleanfixedGutter
is on, and there is a horizontal scrollbar, by default the
gutter will be visible to the left of this scrollbar. If this
option is set to true, it will be covered by an element with
class CodeMirror-gutter-filler.readOnly: boolean|string"nocursor" is given (instead of
simply true), focusing of the editor is also
disallowed.showCursorWhenSelecting: booleanundoDepth: integerhistoryEventDelay: integertabindex: integerautofocus: booleanfromTextArea is
used, and no explicit value is given for this option, it will be
set to true when either the source textarea is focused, or it
has an autofocus attribute and no other element is
focused.Below this a few more specialized, low-level options are listed. These are only useful in very specific situations, you might want to skip them the first time you read this manual.
dragDrop: booleanonDragEvent: function(instance: CodeMirror, event: Event) → booleandragenter, dragover,
or drop event. It will be passed the editor
instance and the event object as arguments. The callback can
choose to handle the event itself, in which case it should
return true to indicate that CodeMirror should not
do anything further.onKeyEvent: function(instance: CodeMirror, event: Event) → booleankeydown, keyup,
and keypress event that CodeMirror captures. It
will be passed two arguments, the editor instance and the key
event. This key event is pretty much the raw key event, except
that a stop() method is always added to it. You
could feed it to, for example, jQuery.Event to
further normalize it.keydown does not stop
the keypress from firing, whereas on others it
does. If you respond to an event, you should probably inspect
its type property and only do something when it
is keydown (or keypress for actions
that need character data).cursorBlinkRate: numbercursorScrollMargin: numbercursorHeight: number0.85),
which causes the cursor to not reach all the way to the bottom
of the line, looks betterresetSelectionOnContextMenu: booleantrue.workTime, workDelay: numberworkTime milliseconds, and then use
timeout to sleep for workDelay milliseconds. The
defaults are 200 and 300, you can change these options to make
the highlighting more or less aggressive.workDelay: numberworkTime.pollInterval: numberflattenSpans: booleanmaxHighlightLength: numberInfinity to turn off
this behavior.crudeMeasuringFrom: numberviewportMargin: integerInfinity to make sure the whole document is
always rendered, and thus the browser's text search works on it.
This will have bad effects on performance of big
documents.Various CodeMirror-related objects emit events, which allow
client code to react to various situations. Handlers for such
events can be registed with the on
and off methods on the objects
that the event fires on. To fire your own events,
use CodeMirror.signal(target, name, args...),
where target is a non-DOM-node object.
An editor instance fires the following events.
The instance argument always refers to the editor
itself.
"change" (instance: CodeMirror, changeObj: object)changeObj is a {from, to, text, removed,
next} object containing information about the changes
that occurred as second argument. from
and to are the positions (in the pre-change
coordinate system) where the change started and ended (for
example, it might be {ch:0, line:18} if the
position is at the beginning of line #19). text is
an array of strings representing the text that replaced the
changed range (split by line). removed is the text
that used to be between from and to,
which is overwritten by this change. If multiple changes
happened during a single operation, the object will have
a next property pointing to another change object
(which may point to another, etc)."beforeChange" (instance: CodeMirror, changeObj: object)changeObj object
has from, to, and text
properties, as with
the "change" event, but
never a next property, since this is fired for each
individual change, and not batched per operation. It also has
a cancel() method, which can be called to cancel
the change, and, if the change isn't coming
from an undo or redo event, an update(from, to,
text) method, which may be used to modify the change.
Undo or redo changes can't be modified, because they hold some
metainformation for restoring old marked ranges that is only
valid for that specific change. All three arguments
to update are optional, and can be left off to
leave the existing value for that field
intact. Note: you may not do anything from
a "beforeChange" handler that would cause changes
to the document or its visualization. Doing so will, since this
handler is called directly from the bowels of the CodeMirror
implementation, probably cause the editor to become
corrupted."cursorActivity" (instance: CodeMirror)"keyHandled" (instance: CodeMirror, name: string, event: Event)name is the name of the handled key (for
example "Ctrl-X" or "'q'"),
and event is the DOM keydown
or keypress event."inputRead" (instance: CodeMirror, changeObj: object)"beforeSelectionChange" (instance: CodeMirror, selection: {head, anchor})selection parameter is an object
with head and anchor properties
holding {line, ch} objects, which the handler can
read and update. Handlers for this event have the same
restriction
as "beforeChange"
handlers — they should not do anything to directly update the
state of the editor."viewportChange" (instance: CodeMirror, from: number, to: number)from and to arguments
give the new start and end of the viewport."swapDoc" (instance: CodeMirror, oldDoc: Doc)swapDoc
method."gutterClick" (instance: CodeMirror, line: integer, gutter: string, clickEvent: Event)mousedown event object as
fourth argument."gutterContextMenu" (instance: CodeMirror, line: integer, gutter: string, contextMenu: Event: Event)contextmenu event. Will pass the editor
instance as first argument, the (zero-based) number of the line
that was clicked as second argument, the CSS class of the
gutter that was clicked as third argument, and the raw
contextmenu mouse event object as fourth argument.
You can preventDefault the event, to signal that
CodeMirror should do no further handling."focus" (instance: CodeMirror)"blur" (instance: CodeMirror)"scroll" (instance: CodeMirror)"update" (instance: CodeMirror)"renderLine" (instance: CodeMirror, line: LineHandle, element: Element)"mousedown",
"dblclick", "contextmenu", "keydown", "keypress",
"keyup", "dragstart", "dragenter",
"dragover", "drop"
(instance: CodeMirror, event: Event)preventDefault the event, or give it a
truthy codemirrorIgnore property, to signal that
CodeMirror should do no further handling.Document objects (instances
of CodeMirror.Doc) emit the
following events:
"change" (doc: CodeMirror.Doc, changeObj: object)changeObj has a similar type as the
object passed to the
editor's "change"
event, but it never has a next property, because
document change events are not batched (whereas editor change
events are)."beforeChange" (doc: CodeMirror.Doc, change: object)"cursorActivity" (doc: CodeMirror.Doc)"beforeSelectionChange" (doc: CodeMirror.Doc, selection: {head, anchor})Line handles (as returned by, for
example, getLineHandle)
support these events:
"delete" ()"change" (line: LineHandle, changeObj: object)change
object is similar to the one passed
to change event on the editor
object.Marked range handles (CodeMirror.TextMarker), as returned
by markText
and setBookmark, emit the
following events:
"beforeCursorEnter" ()"clear" (from: {line, ch}, to: {line, ch})clearOnEnter
or through a call to its clear() method. Will only
be fired once per handle. Note that deleting the range through
text editing does not fire this event, because an undo action
might bring the range back into existence. from
and to give the part of the document that the range
spanned when it was cleared."hide" ()"unhide" ()Line widgets (CodeMirror.LineWidget), returned
by addLineWidget, fire
these events:
"redraw" ()Keymaps are ways to associate keys with functionality. A keymap is an object mapping strings that identify the keys to functions that implement their functionality.
Keys are identified either by name or by character.
The CodeMirror.keyNames object defines names for
common keys and associates them with their key codes. Examples of
names defined here are Enter, F5,
and Q. These can be prefixed
with Shift-, Cmd-, Ctrl-,
and Alt- (in that order!) to specify a modifier. So
for example, Shift-Ctrl-Space would be a valid key
identifier.
Common example: map the Tab key to insert spaces instead of a tab character.
{
Tab: function(cm) {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
cm.replaceSelection(spaces, "end", "+input");
}
}
Alternatively, a character can be specified directly by
surrounding it in single quotes, for example '$'
or 'q'. Due to limitations in the way browsers fire
key events, these may not be prefixed with modifiers.
The CodeMirror.keyMap object associates keymaps
with names. User code and keymap definitions can assign extra
properties to this object. Anywhere where a keymap is expected, a
string can be given, which will be looked up in this object. It
also contains the "default" keymap holding the
default bindings.
The values of properties in keymaps can be either functions of
a single argument (the CodeMirror instance), strings, or
false. Such strings refer to properties of the
CodeMirror.commands object, which defines a number of
common commands that are used by the default keybindings, and maps
them to functions. If the property is set to false,
CodeMirror leaves handling of the key up to the browser. A key
handler function may return CodeMirror.Pass to indicate
that it has decided not to handle the key, and other handlers (or
the default behavior) should be given a turn.
Keys mapped to command names that start with the
characters "go" (which should be used for
cursor-movement actions) will be fired even when an
extra Shift modifier is present (i.e. "Up":
"goLineUp" matches both up and shift-up). This is used to
easily implement shift-selection.
Keymaps can defer to each other by defining
a fallthrough property. This indicates that when a
key is not found in the map itself, one or more other maps should
be searched. It can hold either a single keymap or an array of
keymaps.
When a keymap contains a nofallthrough property
set to true, keys matched against that map will be
ignored if they don't match any of the bindings in the map (no
further child maps will be tried). When
the disableInput property is set
to true, the default effect of inserting a character
will be suppressed when the keymap is active as the top-level
map.
Up to a certain extent, CodeMirror's look can be changed by
modifying style sheet files. The style sheets supplied by modes
simply provide the colors for that mode, and can be adapted in a
very straightforward way. To style the editor itself, it is
possible to alter or override the styles defined
in codemirror.css.
Some care must be taken there, since a lot of the rules in this file are necessary to have CodeMirror function properly. Adjusting colors should be safe, of course, and with some care a lot of other things can be changed as well. The CSS classes defined in this file serve the following roles:
CodeMirrorCodeMirror-scrolloverflow: auto +
fixed height). By default, it does. Setting
the CodeMirror class to have height:
auto and giving this class overflow-x: auto;
overflow-y: hidden; will cause the editor
to resize to fit its
content.CodeMirror-focusedCodeMirror-guttersCodeMirror-linenumbersCodeMirror-linenumberCodeMirror-linenumbers
(plural) element, but rather will be absolutely positioned to
overlay it. Use this to set alignment and text properties for
the line numbers.CodeMirror-linesCodeMirror-cursorCodeMirror-selectedspan elements
with this class.CodeMirror-matchingbracket,
CodeMirror-nonmatchingbracketIf your page's style sheets do funky things to
all div or pre elements (you probably
shouldn't do that), you'll have to define rules to cancel these
effects out again for elements under the CodeMirror
class.
Themes are also simply CSS files, which define colors for
various syntactic elements. See the files in
the theme directory.
A lot of CodeMirror features are only available through its API. Thus, you need to write code (or use addons) if you want to expose them to your users.
Whenever points in the document are represented, the API uses
objects with line and ch properties.
Both are zero-based. CodeMirror makes sure to 'clip' any positions
passed by client code so that they fit inside the document, so you
shouldn't worry too much about sanitizing your coordinates. If you
give ch a value of null, or don't
specify it, it will be replaced with the length of the specified
line.
Methods prefixed with doc. can, unless otherwise
specified, be called both on CodeMirror (editor)
instances and CodeMirror.Doc instances. Methods
prefixed with cm. are only available
on CodeMirror instances.
Constructing an editor instance is done with
the CodeMirror(place: Element|fn(Element),
?option: object) constructor. If the place
argument is a DOM element, the editor will be appended to it. If
it is a function, it will be called, and is expected to place the
editor into the document. options may be an element
mapping option names to values. The options
that it doesn't explicitly specify (or all options, if it is not
passed) will be taken
from CodeMirror.defaults.
Note that the options object passed to the constructor will be mutated when the instance's options are changed, so you shouldn't share such objects between instances.
See CodeMirror.fromTextArea
for another way to construct an editor instance.
doc.getValue(?separator: string) → string"\n").doc.setValue(content: string)doc.getRange(from: {line, ch}, to: {line, ch}, ?separator: string) → string{line, ch} objects. An optional third
argument can be given to indicate the line separator string to
use (defaults to "\n").doc.replaceRange(replacement: string, from: {line, ch}, to: {line, ch})from
and to with the given string. from
and to must be {line, ch}
objects. to can be left off to simply insert the
string at position from.doc.getLine(n: integer) → stringn.doc.setLine(n: integer, text: string)n.doc.removeLine(n: integer)doc.lineCount() → integerdoc.firstLine() → integerdoc.lastLine() → integerdoc.lineCount() - 1,
but for linked sub-views,
it might return other values.doc.getLineHandle(num: integer) → LineHandledoc.getLineNumber(handle: LineHandle) → integernull when it is no longer in the
document).doc.eachLine(f: (line: LineHandle))doc.eachLine(start: integer, end: integer, f: (line: LineHandle))start
and end line numbers are given, the range
from start up to (not including) end,
and call f for each line, passing the line handle.
This is a faster way to visit a range of line handlers than
calling getLineHandle
for each of them. Note that line handles have
a text property containing the line's content (as a
string).doc.markClean()changeGeneration,
which allows multiple subsystems to track different notions of
cleanness without interfering.doc.changeGeneration() → integerisClean to test whether
any edits were made (and not undone) in the meantime.doc.isClean(?generation: integer) → booleanmarkClean if no
argument is passed, or since the matching call
to changeGeneration
if a generation value is given.doc.getSelection() → stringdoc.replaceSelection(replacement: string, ?collapse: string)collapse argument can be used to change
this—passing "start" or "end" will
collapse the selection to the start or end of the inserted
text.doc.getCursor(?start: string) → {line, ch}start is a an optional string indicating which
end of the selection to return. It may
be "start", "end", "head"
(the side of the selection that moves when you press
shift+arrow), or "anchor" (the fixed side of the
selection). Omitting the argument is the same as
passing "head". A {line, ch} object
will be returned.doc.somethingSelected() → booleandoc.setCursor(pos: {line, ch}){line, ch} object, or the line and the
character as two separate parameters.doc.setSelection(anchor: {line, ch}, ?head: {line, ch})anchor
and head should be {line, ch}
objects. head defaults to anchor when
not given.doc.extendSelection(from: {line, ch}, ?to: {line, ch})setSelection, but
will, if shift is held or
the extending flag is set, move the
head of the selection while leaving the anchor at its current
place. to is optional, and can be passed to
ensure a region (for example a word or paragraph) will end up
selected (in addition to whatever lies between that region and
the current anchor).doc.setExtending(value: boolean)extendSelection
to leave the selection anchor in place.cm.hasFocus() → booleancm.findPosH(start: {line, ch}, amount: integer, unit: string, visually: boolean) → {line, ch, ?hitSide: boolean}start is a {line, ch}
object, amount an integer (may be negative),
and unit one of the
string "char", "column",
or "word". Will return a position that is produced
by moving amount times the distance specified
by unit. When visually is true, motion
in right-to-left text will be visual rather than logical. When
the motion was clipped by hitting the end or start of the
document, the returned value will have a hitSide
property set to true.cm.findPosV(start: {line, ch}, amount: integer, unit: string) → {line, ch, ?hitSide: boolean}findPosH,
but used for vertical motion. unit may
be "line" or "page". The other
arguments and the returned value have the same interpretation as
they have in findPosH.cm.setOption(option: string, value: any)option
should the name of an option,
and value should be a valid value for that
option.cm.getOption(option: string) → anycm.addKeyMap(map: object, bottom: boolean)extraKeys
option. Maps added in this way have a higher precedence than
the extraKeys
and keyMap options,
and between them, the maps added earlier have a lower precedence
than those added later, unless the bottom argument
was passed, in which case they end up below other keymaps added
with this method.cm.removeKeyMap(map: object)addKeyMap. Either
pass in the keymap object itself, or a string, which will be
compared against the name property of the active
keymaps.cm.addOverlay(mode: string|object, ?options: object)mode can be a mode
spec or a mode object (an object with
a token method).
The options parameter is optional. If given, it
should be an object. Currently, only the opaque
option is recognized. This defaults to off, but can be given to
allow the overlay styling, when not null, to
override the styling of the base mode entirely, instead of the
two being applied together.cm.removeOverlay(mode: string|object)mode
parameter to addOverlay,
or a string that corresponds to the name propery of
that value, to remove an overlay again.cm.on(type: string, func: (...args))CodeMirror.on(object, type, func) version
that allows registering of events on any object.cm.off(type: string, func: (...args))CodeMirror.off(object, type,
func) also exists.Each editor is associated with an instance
of CodeMirror.Doc, its document. A document
represents the editor content, plus a selection, an undo history,
and a mode. A document can only be
associated with a single editor at a time. You can create new
documents by calling the CodeMirror.Doc(text, mode,
firstLineNumber) constructor. The last two arguments are
optional and can be used to set a mode for the document and make
it start at a line number other than 0, respectively.
cm.getDoc() → Docdoc.getEditor() → CodeMirrornull.cm.swapDoc(doc: CodeMirror.Doc) → Docdoc.copy(copyHistory: boolean) → DoccopyHistory is true, the history will also be
copied. Can not be called directly on an editor.doc.linkedDoc(options: object) → Docfrom: integerto: integermode: string|objectdoc.unlinkDoc(doc: CodeMirror.Doc)doc.iterLinkedDocs(function: (doc: CodeMirror.Doc, sharedHist: boolean))doc.undo()doc.redo()doc.historySize() → {undo: integer, redo: integer}{undo, redo} properties,
both of which hold integers, indicating the amount of stored
undo and redo operations.doc.clearHistory()doc.getHistory() → objectdoc.setHistory(history: object)getHistory. Note that
this will have entirely undefined results if the editor content
isn't also the same as it was when getHistory was
called.doc.markText(from: {line, ch}, to: {line, ch}, ?options: object) → TextMarkerfrom and to should
be {line, ch} objects. The options
parameter is optional. When given, it should be an object that
may contain the following configuration options:
className: stringinclusiveLeft: booleaninclusiveRight: booleaninclusiveLeft,
but for the right side.atomic: booleaninclusiveLeft
and inclusiveRight have a different meaning—they
will prevent the cursor from being placed respectively
directly before and directly after the range.collapsed: booleanclearOnEnter: boolean"clear" event
fired on the range handle can be used to be notified when this
happens.replacedWith: ElementhandleMouseEvents: booleanreplacedWith is given, this determines
whether the editor will capture mouse and drag events
occurring in this widget. Default is false—the events will be
left alone for the default browser handler, or specific
handlers on the widget, to capture.readOnly: booleansetValue to reset
the whole document. Note: adding a read-only span
currently clears the undo history of the editor, because
existing undo events being partially nullified by read-only
spans would corrupt the history (in the current
implementation).addToHistory: booleanstartStyle: stringendStyle: stringstartStyle, but for the rightmost span.title:
stringtitle attribute with the
given value.shared to true to make the
marker appear in all documents. By default, a marker appears
only in its target document.CodeMirror.TextMarker), which
exposes three methods:
clear(), to remove the mark,
find(), which returns
a {from, to} object (both holding document
positions), indicating the current position of the marked range,
or undefined if the marker is no longer in the
document, and finally changed(),
which you can call if you've done something that might change
the size of the marker (for example changing the content of
a replacedWith
node), and want to cheaply update the display.doc.setBookmark(pos: {line, ch}, ?options: object) → TextMarkerfind() and clear(). The first
returns the current position of the bookmark, if it is still in
the document, and the second explicitly removes the bookmark.
The options argument is optional. If given, the following
properties are recognized:
widget: ElementreplacedWith
option to markText).insertLeft: booleandoc.findMarksAt(pos: {line, ch}) → array<TextMarker>doc.getAllMarks() → array<TextMarker>cm.setGutterMarker(line: integer|LineHandle, gutterID: string, value: Element) → LineHandlegutters option)
to the given value. Value can be either null, to
clear the marker, or a DOM element, to set it. The DOM element
will be shown in the specified gutter next to the specified
line.cm.clearGutter(gutterID: string)cm.addLineClass(line: integer|LineHandle, where: string, class: string) → LineHandleline
can be a number or a line handle. where determines
to which element this class should be applied, can can be one
of "text" (the text element, which lies in front of
the selection), "background" (a background element
that will be behind the selection), or "wrap" (the
wrapper node that wraps all of the line's elements, including
gutter elements). class should be the name of the
class to apply.cm.removeLineClass(line: integer|LineHandle, where: string, class: string) → LineHandleline can be a
line handle or number. where should be one
of "text", "background",
or "wrap"
(see addLineClass). class
can be left off to remove all classes for the specified node, or
be a string to remove only a specific class.cm.lineInfo(line: integer|LineHandle) → object{line, handle, text,
gutterMarkers, textClass, bgClass, wrapClass, widgets},
where gutterMarkers is an object mapping gutter IDs
to marker elements, and widgets is an array
of line widgets attached to this
line, and the various class properties refer to classes added
with addLineClass.cm.addWidget(pos: {line, ch}, node: Element, scrollIntoView: boolean)node, which should be an absolutely
positioned DOM node, into the editor, positioned right below the
given {line, ch} position.
When scrollIntoView is true, the editor will ensure
that the entire node is visible (if possible). To remove the
widget again, simply use DOM methods (move it somewhere else, or
call removeChild on its parent).cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object) → LineWidgetline should be either an integer or a
line handle, and node should be a DOM node, which
will be displayed below the given line. options,
when given, should be an object that configures the behavior of
the widget. The following options are supported (all default to
false):
coverGutter: booleannoHScroll: booleanabove: booleanshowIfHidden: booleanhandleMouseEvents: booleaninsertAt: integerline property
pointing at the line handle that it is associated with, and the following methods:
clear()changed()cm.setSize(width: number|string, height: number|string)width and height
can be either numbers (interpreted as pixels) or CSS units
("100%", for example). You can
pass null for either of them to indicate that that
dimension should not be changed.cm.scrollTo(x: number, y: number)null
or undefined to have no effect.cm.getScrollInfo() → {left, top, width, height, clientWidth, clientHeight}{left, top, width, height, clientWidth,
clientHeight} object that represents the current scroll
position, the size of the scrollable area, and the size of the
visible area (minus scrollbars).cm.scrollIntoView(what: {line, ch}|{left, top, right, bottom}|{from, to}|null, ?margin: number)what may
be null to scroll the cursor into view,
a {line, ch} position to scroll a character into
view, a {left, top, right, bottom} pixel range (in
editor-local coordinates), or a range {from, to}
containing either two character positions or two pixel squares.
The margin parameter is optional. When given, it
indicates the amount of vertical pixels around the given area
that should be made visible as well.cm.cursorCoords(where: boolean|{line, ch}, mode: string) → {left, top, bottom}{left, top, bottom} object
containing the coordinates of the cursor position.
If mode is "local", they will be
relative to the top-left corner of the editable document. If it
is "page" or not given, they are relative to the
top-left corner of the page. where can be a boolean
indicating whether you want the start (true) or the
end (false) of the selection, or, if a {line,
ch} object is given, it specifies the precise position at
which you want to measure.cm.charCoords(pos: {line, ch}, ?mode: string) → {left, right, top, bottom}pos should be a {line, ch}
object. This differs from cursorCoords in that
it'll give the size of the whole character, rather than just the
position that the cursor would have when it would sit at that
position.cm.coordsChar(object: {left, top}, ?mode: string) → {line, ch}{left, top} object, returns
the {line, ch} position that corresponds to it. The
optional mode parameter determines relative to what
the coordinates are interpreted. It may
be "window", "page" (the default),
or "local".cm.lineAtHeight(height: number, ?mode: string) → numbermode can be one of the same strings
that coordsChar
accepts.cm.heightAtLine(line: number, ?mode: string) → numbermode
(see coordsChar), which
defaults to "page". When a line below the bottom of
the document is specified, the returned value is the bottom of
the last line in the document.cm.defaultTextHeight() → numbercm.defaultCharWidth() → numbercm.getViewport() → {from: number, to: number}{from, to} object indicating the
start (inclusive) and end (exclusive) of the currently rendered
part of the document. In big documents, when most content is
scrolled out of view, CodeMirror will only render the visible
part, and a margin around it. See also
the viewportChange
event.cm.refresh()When writing language-aware functionality, it can often be useful to hook into the knowledge that the CodeMirror language mode has. See the section on modes for a more detailed description of how these work.
doc.getMode() → objectgetOption("mode"), which gives you
the mode specification, rather than the resolved, instantiated
mode object.doc.getModeAt(pos: {line, ch}) → objectgetMode for
simple modes, but will return an inner mode for nesting modes
(such as htmlmixed).cm.getTokenAt(pos: {line, ch}, ?precise: boolean) → object{line, ch} object). The
returned object has the following properties:
startendstringtype"keyword"
or "comment" (may also be null).stateprecise is true, the token will be guaranteed to be accurate based on recent edits. If false or
not specified, the token will use cached state information, which will be faster but might not be accurate if
edits were recently made and highlighting has not yet completed.
cm.getTokenTypeAt(pos: {line, ch}) → stringgetTokenAt useful for
when you just need the type of the token at a given position,
and no other information. Will return null for
unstyled tokens, and a string, potentially containing multiple
space-separated style names, otherwise.cm.getHelper(pos: {line, ch}, type: string) → helpertype argument provides the helper namespace
(see
also registerHelper),
in which the value will be looked up. The key that is used
depends on the mode active at the given
position. If the mode object contains a property with the same
name as the type argument, that is tried first.
Next, the mode's helperType, if any, is tried. And
finally, the mode's name.cm.getStateAfter(?line: integer, ?precise: boolean) → objectprecise is defined
as in getTokenAt().cm.operation(func: () → any) → anycm.indentLine(line: integer, ?dir: string|integer)"smart") may be one of:
"prev""smart""prev" otherwise."add""subtract"<integer>cm.toggleOverwrite(?value: bool)doc.posFromIndex(index: integer) → {line, ch}{line, ch} object for a
zero-based index who's value is relative to the start of the
editor's text. If the index is out of range of the text then
the returned object is clipped to start or end of the text
respectively.doc.indexFromPos(object: {line, ch}) → integerposFromIndex.cm.focus()cm.getInputField() → TextAreaElementcm.getWrapperElement() → Elementcm.getScrollerElement() → Elementcm.getGutterElement() → ElementThe CodeMirror object itself provides
several useful properties.
CodeMirror.version: string"major.minor.patch",
where patch is zero for releases, and something
else (usually one) for dev snapshots.CodeMirror.fromTextArea(textArea: TextAreaElement, ?config: object)cm.save()cm.toTextArea()cm.getTextArea() → TextAreaElementCodeMirror.defaults: objectCodeMirror.defineExtension(name: string, value: any)defineExtension. This will cause the given
value (usually a method) to be added to all CodeMirror instances
created from then on.CodeMirror.defineDocExtension(name: string, value: any)defineExtension,
but the method will be added to the interface
for Doc objects instead.CodeMirror.defineOption(name: string,
default: any, updateFunc: function)defineOption can be used to define new options for
CodeMirror. The updateFunc will be called with the
editor instance and the new value when an editor is initialized,
and whenever the option is modified
through setOption.CodeMirror.defineInitHook(func: function)CodeMirror.defineInitHook. Give it a function as
its only argument, and from then on, that function will be called
(with the instance as argument) whenever a new CodeMirror instance
is initialized.CodeMirror.registerHelper(type: string, name: string, value: helper)name in
the given namespace (type). This is used to define
functionality that may be looked up by mode. Will create (if it
doesn't already exist) a property on the CodeMirror
object for the given type, pointing to an object
that maps names to values. I.e. after
doing CodeMirror.registerHelper("hint", "foo",
myFoo), the value CodeMirror.hint.foo will
point to myFoo.CodeMirror.Pos(line: integer, ?ch: integer){line, ch} objects that
are used to represent positions in editor documents.CodeMirror.changeEnd(change: object) → {line, ch}from, to,
and text properties, as passed to
various event handlers). The
returned position will be the end of the changed
range, after the change is applied.The addon directory in the distribution contains a
number of reusable components that implement extra editor
functionality. In brief, they are:
dialog/dialog.jsopenDialog method to CodeMirror instances,
which can be called with an HTML fragment that provides the
prompt (should include an input tag), and a
callback function that is called when text has been entered.
Depends on addon/dialog/dialog.css.search/searchcursor.jsgetSearchCursor(query, start, caseFold) →
cursor method to CodeMirror instances, which can be used
to implement search/replace functionality. query
can be a regular expression or a string (only strings will match
across lines—if they contain newlines). start
provides the starting position of the search. It can be
a {line, ch} object, or can be left off to default
to the start of the document. caseFold is only
relevant when matching a string. It will cause the search to be
case-insensitive. A search cursor has the following methods:
findNext() → booleanfindPrevious() → booleanmatch method, in case you
want to extract matched groups.from() → {line, ch}to() → {line, ch}findNext or findPrevious did
not return false. They will return {line, ch}
objects pointing at the start and end of the match.replace(text: string)search/search.jssearchcursor.js, and will make use
of openDialog when
available to make prompting for search queries less ugly.edit/matchbrackets.jsmatchBrackets which, when set
to true, causes matching brackets to be highlighted whenever the
cursor is next to them. It also adds a
method matchBrackets that forces this to happen
once, and a method findMatchingBracket that can be
used to run the bracket-finding algorithm that this uses
internally.edit/closebrackets.jsautoCloseBrackets that will
auto-close brackets and quotes when typed. By default, it'll
auto-close ()[]{}''"", but you can pass it a string
similar to that (containing pairs of matching characters), or an
object with pairs and
optionally explode properties to customize
it. explode should be a similar string that gives
the pairs of characters that, when enter is pressed between
them, should have the second character also moved to its own
line. Demo here.matchTags that, when enabled,
will cause the tags around the cursor to be highlighted (using
the CodeMirror-matchingtag class). Also
defines
a command toMatchingTag,
which you can bind a key to in order to jump to the tag mathing
the one under the cursor. Depends on
the addon/fold/xml-fold.js
addon. Demo here.edit/trailingspace.jsshowTrailingSpace which, when
enabled, adds the CSS class cm-trailingspace to
stretches of whitespace at the end of lines.
The demo has a nice
squiggly underline style for this class.edit/closetag.jsedit/continuelist.js"newlineAndIndentContinueMarkdownList" command
command that can be bound to enter to automatically
insert the leading characters for continuing a list. See
the Markdown mode
demo.comment/comment.jslineComment(from: {line, ch}, to: {line, ch}, ?options: object)blockComment when no line comment
style is defined for the mode.blockComment(from: {line, ch}, to: {line, ch}, ?options: object)lineComment when no block comment
style is defined for the mode.uncomment(from: {line, ch}, to: {line, ch}, ?options: object) → booleantrue if a comment range was found and
removed, false otherwise.options object accepted by these methods may
have the following properties:
blockCommentStart, blockCommentEnd, blockCommentLead, lineComment: stringpadding: stringcommentBlankLines: booleanindent: booleanfullLines: booleantrue.toggleComment command,
which will try to uncomment the current selection, and if that
fails, line-comments it.fold/foldcode.jsfoldCode method
to editor instances, which will try to do a code fold starting
at the given line, or unfold the fold that is already present.
The method takes as first argument the position that should be
folded (may be a line number or
a Pos), and as second optional
argument either a range-finder function, or an options object,
supporting the following properties:
rangeFinder: fn(CodeMirror, Pos)getHelper with
a "fold" type to find one that's appropriate for
the mode. There are files in
the addon/fold/
directory providing CodeMirror.fold.brace, which
finds blocks in brace languages (JavaScript, C, Java,
etc), CodeMirror.fold.indent, for languages where
indentation determines block structure (Python, Haskell),
and CodeMirror.fold.xml, for XML-style languages,
and CodeMirror.fold.comment, for folding comment
blocks.widget: string|ElementCodeMirror-foldmarker, or a DOM node.scanUp: booleanminFoldSize: integerfold/foldgutter.jsfoldGutter, which can be
used to create a gutter with markers indicating the blocks that
can be folded. Create a gutter using
the gutters option,
giving it the class CodeMirror-foldgutter or
something else if you configure the addon to use a different
class, and this addon will show markers next to folded and
foldable blocks, and handle clicks in this gutter. Note that
CSS styles should be applied to make the gutter, and the fold
markers within it, visible. A default set of CSS styles are
available in:
addon/fold/foldgutter.css
.
The option
can be either set to true, or an object containing
the following optional option fields:
gutter: string"CodeMirror-foldgutter". You will have to
style this yourself to give it a width (and possibly a
background). See the default gutter style rules above.indicatorOpen: string | Element"CodeMirror-foldgutter-open".indicatorFolded: string | Element"CodeMirror-foldgutter-folded".rangeFinder: fn(CodeMirror, Pos)getHelper will be
used to determine a default.runmode/runmode.jsrunmode/colorize.jsrunmode addon (or
its standalone variant). Provides
a CodeMirror.colorize function that can be called
with an array (or other array-ish collection) of DOM nodes that
represent the code snippets. By default, it'll get
all pre tags. Will read the data-lang
attribute of these nodes to figure out their language, and
syntax-color their content using the relevant CodeMirror mode
(you'll have to load the scripts for the relevant modes
yourself). A second argument may be provided to give a default
mode, used when no language attribute is found for a node. Used
in this manual to highlight example code.mode/overlay.jsCodeMirror.overlayMode, which is used to
create such a mode. See this
demo for a detailed example.mode/multiplex.jsCodeMirror.multiplexingMode which, when
given as first argument a mode object, and as other arguments
any number of {open, close, mode [, delimStyle, innerStyle]}
objects, will return a mode object that starts parsing using the
mode passed as first argument, but will switch to another mode
as soon as it encounters a string that occurs in one of
the open fields of the passed objects. When in a
sub-mode, it will go back to the top mode again when
the close string is encountered.
Pass "\n" for open or close
if you want to switch on a blank line.
delimStyle is specified, it will be the token
style returned for the delimiter tokens.innerStyle is specified, it will be the token
style added for each inner mode token.hint/show-hint.jsCodeMirror.showHint, which takes a
CodeMirror instance, a hinting function, and optionally an
options object, and pops up a widget that allows the user to
select a completion. Hinting functions are function that take an
editor instance and an optional options object, and return
a {list, from, to} object, where list
is an array of strings or objects (the completions),
and from and to give the start and end
of the token that is being completed as {line, ch}
objects. If no hinting function is given, the addon will try to
use getHelper with
the "hint" type to find one. When completions
aren't simple strings, they should be objects with the folowing
properties:
text: stringdisplayText: stringclassName: stringrender: fn(Element, self, data)hint: fn(CodeMirror, self, data)async: boolean(cm, callback, ?options), and the completion
interface will only be popped up when the hinting function
calls the callback, passing it the object holding the
completions.completeSingle: booleanalignWithWord: booleancloseOnUnfocus: booleancustomKeys: keymapmoveFocus(n), setFocus(n), pick(),
and close() methods (see the source for details),
that can be used to change the focused element, pick the
current element or close the menu.extraKeys: keymapcustomKeys above, but the bindings will
be added to the set of default bindings, instead of replacing
them."shown" ()"select" (completion, Element)"close" ()addon/hint/show-hint.css. Check
out the demo for an
example.hint/javascript-hint.jsCodeMirror.hint.javascript) and CoffeeScript
(CodeMirror.hint.coffeescript) code. This will
simply use the JavaScript environment that the editor runs in as
a source of information about objects and their properties.hint/xml-hint.jsCodeMirror.hint.xml, which produces
hints for XML tagnames, attribute names, and attribute values,
guided by a schemaInfo option (a property of the
second argument passed to the hinting function, or the third
argument passed to CodeMirror.showHint)."!top" property
containing a list of the names of valid top-level tags. The
values of the properties should be objects with optional
properties children (an array of valid child
element names, omit to simply allow all tags to appear)
and attrs (an object mapping attribute names
to null for free-form attributes, and an array of
valid values for restricted
attributes). Demo
here.hint/html-hint.jsCodeMirror.htmlSchema that you can pass to
as a schemaInfo option, and
a CodeMirror.hint.html hinting function that
automatically calls CodeMirror.hint.xml with this
schema data. See
the demo.hint/css-hint.jsCodeMirror.hint.css.hint/python-hint.jsCodeMirror.hint.python.hint/anyword-hint.jsCodeMirror.hint.anyword) that simply looks for
words in the nearby code and completes to those. Takes two
optional options, word, a regular expression that
matches words (sequences of one or more character),
and range, which defines how many lines the addon
should scan when completing (defaults to 500).hint/sql-hint.jsCodeMirror.hint.sql.hint/pig-hint.jsCodeMirror.hint.pig.search/match-highlighter.jshighlightSelectionMatches option that
can be enabled to highlight all instances of a currently
selected word. Can be set either to true or to an object
containing the following options: minChars, for the
minimum amount of selected characters that triggers a highlight
(default 2), style, for the style to be used to
highlight the matches (default "matchhighlight",
which will correspond to CSS
class cm-matchhighlight),
and showToken which can be set to true
or to a regexp matching the characters that make up a word. When
enabled, it causes the current word to be highlighted when
nothing is selected (defaults to off).
Demo here.lint/lint.jsjson-lint.js,
javascript-lint.js,
and css-lint.js
in the same directory). Defines a lint option that
can be set to a warning source (for
example CodeMirror.lint.javascript), or
to true, in which
case getHelper with
type "lint" is used to determined a validator
function. Depends on addon/lint/lint.css. A demo
can be found here.selection/mark-selection.jsCodeMirror-selectedtext when the styleSelectedText option
is enabled. Useful to change the colour of the selection (in addition to the background),
like in this demo.selection/active-line.jsstyleActiveLine option that, when enabled,
gives the wrapper of the active line the class CodeMirror-activeline,
and adds a background with the class CodeMirror-activeline-background.
is enabled. See the demo.mode/loadmode.jsCodeMirror.requireMode(modename,
callback) function that will try to load a given mode and
call the callback when it succeeded. You'll have to
set CodeMirror.modeURL to a string that mode paths
can be constructed from, for
example "mode/%N/%N.js"—the %N's will
be replaced with the mode name. Also
defines CodeMirror.autoLoadMode(instance, mode),
which will ensure the given mode is loaded and cause the given
editor instance to refresh its mode when the loading
succeeded. See the demo.comment/continuecomment.jscontinueComments option, which can be
set to true to have the editor prefix new lines inside C-like
block comments with an asterisk when Enter is pressed. It can
also be set to a string in order to bind this functionality to a
specific key..display/placeholder.jsplaceholder option that can be used to
make text appear in the editor when it is empty and not focused.
Also gives the editor a CodeMirror-empty CSS class
whenever it doesn't contain any text.
See the demo.display/fullscreen.jsfullScreen that, when set
to true, will make the editor full-screen (as in,
taking up the whole browser window). Depends
on fullscreen.css. Demo
here.wrap/hardwrap.jswrapParagraph(?pos: {line, ch}, ?options: object)pos is not given, it defaults to the cursor
position.wrapRange(from: {line, ch}, to: {line, ch}, ?options: object)wrapParagraphsInRange(from: {line, ch}, to: {line, ch}, ?options: object)paragraphStart, paragraphEnd: RegExpcolumn: numberwrapOn: RegExpkillTrailingSpace: booleanmerge/merge.jsCodeMirror.MergeView
constructor takes arguments similar to
the CodeMirror
constructor, first a node to append the interface to, and then
an options object. Two extra optional options are
recognized, origLeft and origRight,
which may be strings that provide original versions of the
document, which will be shown to the left and right of the
editor in non-editable CodeMirror instances. The merge interface
will highlight changes between the editable document and the
original(s) (demo).tern/tern.jsModes typically consist of a single JavaScript file. This file defines, in the simplest case, a lexer (tokenizer) for your language—a function that takes a character stream as input, advances it past a token, and returns a style for that token. More advanced modes can also handle indentation for the language.
The mode script should
call CodeMirror.defineMode to
register itself with CodeMirror. This function takes two
arguments. The first should be the name of the mode, for which you
should use a lowercase string, preferably one that is also the
name of the files that define the mode (i.e. "xml" is
defined in xml.js). The second argument should be a
function that, given a CodeMirror configuration object (the thing
passed to the CodeMirror function) and an optional
mode configuration object (as in
the mode option), returns
a mode object.
Typically, you should use this second argument
to defineMode as your module scope function (modes
should not leak anything into the global scope!), i.e. write your
whole mode inside this function.
The main responsibility of a mode script is parsing the content of the editor. Depending on the language and the amount of functionality desired, this can be done in really easy or extremely complicated ways. Some parsers can be stateless, meaning that they look at one element (token) of the code at a time, with no memory of what came before. Most, however, will need to remember something. This is done by using a state object, which is an object that is always passed when reading a token, and which can be mutated by the tokenizer.
Modes that use a state must define
a startState method on their mode
object. This is a function of no arguments that produces a state
object to be used at the start of a document.
The most important part of a mode object is
its token(stream, state) method. All
modes must define this method. It should read one token from the
stream it is given as an argument, optionally update its state,
and return a style string, or null for tokens that do
not have to be styled. For your styles, you are encouraged to use
the 'standard' names defined in the themes (without
the cm- prefix). If that fails, it is also possible
to come up with your own and write your own CSS theme file.
A typical token string would
be "variable" or "comment". Multiple
styles can be returned (separated by spaces), for
example "string error" for a thing that looks like a
string but is invalid somehow (say, missing its closing quote).
When a style is prefixed by "line-"
or "line-background-", the style will be applied to
the whole line, analogous to what
the addLineClass method
does—styling the "text" in the simple case, and
the "background" element
when "line-background-" is prefixed.
The stream object that's passed
to token encapsulates a line of code (tokens may
never span lines) and our current position in that line. It has
the following API:
eol() → booleansol() → booleanpeek() → stringnull at the end of the
line.next() → stringnull when no more characters are
available.eat(match: string|regexp|function(char: string) → boolean) → stringmatch can be a character, a regular expression,
or a function that takes a character and returns a boolean. If
the next character in the stream 'matches' the given argument,
it is consumed and returned. Otherwise, undefined
is returned.eatWhile(match: string|regexp|function(char: string) → boolean) → booleaneat with the given argument,
until it fails. Returns true if any characters were eaten.eatSpace() → booleaneatWhile when matching
white-space.skipToEnd()skipTo(ch: string) → booleanmatch(pattern: string, ?consume: boolean, ?caseFold: boolean) → booleanmatch(pattern: regexp, ?consume: boolean) → array<string>eat—if consume is true
or not given—or a look-ahead that doesn't update the stream
position—if it is false. pattern can be either a
string or a regular expression starting with ^.
When it is a string, caseFold can be set to true to
make the match case-insensitive. When successfully matching a
regular expression, the returned value will be the array
returned by match, in case you need to extract
matched groups.backUp(n: integer)n characters. Backing it up
further than the start of the current token will cause things to
break, so be careful.column() → integerindentation() → integercurrent() → stringBy default, blank lines are simply skipped when
tokenizing a document. For languages that have significant blank
lines, you can define
a blankLine(state) method on your
mode that will get called whenever a blank line is passed over, so
that it can update the parser state.
Because state object are mutated, and CodeMirror
needs to keep valid versions of a state around so that it can
restart a parse at any line, copies must be made of state objects.
The default algorithm used is that a new state object is created,
which gets all the properties of the old object. Any properties
which hold arrays get a copy of these arrays (since arrays tend to
be used as mutable stacks). When this is not correct, for example
because a mode mutates non-array properties of its state object, a
mode object should define
a copyState method, which is given a
state and should return a safe copy of that state.
If you want your mode to provide smart indentation
(through the indentLine
method and the indentAuto
and newlineAndIndent commands, to which keys can be
bound), you must define
an indent(state, textAfter) method
on your mode object.
The indentation method should inspect the given state object,
and optionally the textAfter string, which contains
the text on the line that is being indented, and return an
integer, the amount of spaces to indent. It should usually take
the indentUnit
option into account. An indentation method may
return CodeMirror.Pass to indicate that it
could not come up with a precise indentation.
To work well with
the commenting addon, a mode may
define lineComment (string that
starts a line
comment), blockCommentStart, blockCommentEnd
(strings that start and end block comments),
and blockCommentLead (a string to put at the start of
continued lines in a block comment). All of these are
optional.
Finally, a mode may define
an electricChars property, which should hold a string
containing all the characters that should trigger the behaviour
described for
the electricChars
option.
So, to summarize, a mode must provide
a token method, and it may
provide startState, copyState,
and indent methods. For an example of a trivial mode,
see the diff mode, for a more
involved example, see the C-like
mode.
Sometimes, it is useful for modes to nest—to have one
mode delegate work to another mode. An example of this kind of
mode is the mixed-mode HTML
mode. To implement such nesting, it is usually necessary to
create mode objects and copy states yourself. To create a mode
object, there are CodeMirror.getMode(options,
parserConfig), where the first argument is a configuration
object as passed to the mode constructor function, and the second
argument is a mode specification as in
the mode option. To copy a
state object, call CodeMirror.copyState(mode, state),
where mode is the mode that created the given
state.
In a nested mode, it is recommended to add an
extra method, innerMode which, given
a state object, returns a {state, mode} object with
the inner mode and its state for the current position. These are
used by utility scripts such as the tag
closer to get context information. Use
the CodeMirror.innerMode helper function to, starting
from a mode and a state, recursively walk down to the innermost
mode and state.
To make indentation work properly in a nested parser, it is
advisable to give the startState method of modes that
are intended to be nested an optional argument that provides the
base indentation for the block of code. The JavaScript and CSS
parser do this, for example, to allow JavaScript and CSS code
inside the mixed-mode HTML mode to be properly indented.
It is possible, and encouraged, to associate
your mode, or a certain configuration of your mode, with
a MIME type. For
example, the JavaScript mode associates itself
with text/javascript, and its JSON variant
with application/json. To do this,
call CodeMirror.defineMIME(mime,
modeSpec), where modeSpec can be a string or
object specifying a mode, as in
the mode option.
Sometimes, it is useful to add or override mode
object properties from external code.
The CodeMirror.extendMode function
can be used to add properties to mode objects produced for a
specific mode. Its first argument is the name of the mode, its
second an object that specifies the properties that should be
added. This is mostly useful to add utilities that can later be
looked up through getMode.
Contact me if you'd like your project to be added to this list.
21-10-2013: Version 3.19:
23-09-2013: Version 3.18:
Emergency release to fix a problem in 3.17
where .setOption("lineNumbers", false) would raise an
error.
23-09-2013: Version 3.17:
css-lint, css-hint.box-sizing.21-08-2013: Version 3.16:
CodeMirror.fold.comment.29-07-2013: Version 3.15:
getModeAt.20-06-2013: Version 3.14:
markText
and addLineWidget
now take a handleMouseEvents option.lineAtHeight,
getTokenTypeAt.changeGeneration
and isClean."keyHandled"
and "inputRead".20-05-2013: Version 3.13:
cursorScrollMargin and coverGutterNextToScrollbar.19-04-2013: Version 3.12:
maxHighlightLength
and historyEventDelay.addToHistory
option for markText.20-03-2013: Version 3.11:
collapserange,
formatting, and simple-hint
addons. plsql and mysql modes
(use sql mode).continuecomment
addon now exposes an option, rather than a command.placeholder, HTML completion.hasFocus, defaultCharWidth.beforeCursorEnter, renderLine.show-hint completion
dialog addon.21-02-2013: Version 3.1:
CodeMirror.Pass to signal they
didn't handle the key.simple-hint.js.insertLeft option
to setBookmark.eachLine
method to iterate over a document."beforeChange"
and "beforeSelectionChange"
events."hide"
and "unhide"
events to marked ranges.coordsChar's
interpretation of its argument to match the documentation.25-01-2013: Version 3.02:
Single-bugfix release. Fixes a problem that prevents CodeMirror instances from being garbage-collected after they become unused.
21-01-2013: Version 3.01:
/addon. You might have to adjust your
paths.rtlMoveVisually option.showIfHidden option for line widgets.fixedGutter option.10-12-2012: Version 3.0:
New major version. Only partially backwards-compatible. See the upgrading guide for more information. Changes since release candidate 2:
20-11-2012: Version 3.0, release candidate 2:
addKeyMap and removeKeyMap methods.formatting and closetag add-ons.20-11-2012: Version 3.0, release candidate 1:
addLineClass
and removeLineClass,
drop setLineClass.isClean/markClean methods.compoundChange method, use better undo-event-combining heuristic.22-10-2012: Version 3.0, beta 2:
gutterClick event.cursorHeight option.viewportMargin option.flattenSpans option.19-09-2012: Version 3.0, beta 1:
21-01-2013: Version 2.38:
Integrate some bugfixes, enhancements to the vim keymap, and new modes (D, Sass, APL) from the v3 branch.
20-12-2012: Version 2.37:
20-11-2012: Version 2.36:
scrollIntoView public.defaultTextHeight method.22-10-2012: Version 2.35:
markText/undo interaction.defineInitHook function.19-09-2012: Version 2.34:
compareStates is no longer needed.onHighlightComplete no longer works.CodeMirror.version property.23-08-2012: Version 2.33:
getViewPort and onViewportChange API.false disabling handling (again).innerHTML. Remove CodeMirror.htmlEscape.23-07-2012: Version 2.32:
Emergency fix for a bug where an editor with line wrapping on IE will break when there is no scrollbar.
20-07-2012: Version 2.31:
setSize method for programmatic resizing.getHistory and setHistory methods.getValue and getRange.22-06-2012: Version 2.3:
getScrollInfo method.23-05-2012: Version 2.25:
23-04-2012: Version 2.24:
dragDrop
and onDragEvent
options.compoundChange API method.catchall in key maps,
add nofallthrough boolean field instead.26-03-2012: Version 2.23:
setLineClass.charCoords
and cursorCoords with a mode argument.autofocus option.findMarksAt method.27-02-2012: Version 2.22:
autoClearEmptyLines option.27-01-2012: Version 2.21:
smartIndent
option.readOnly-mode.scrollTo method.20-12-2011: Version 2.2:
coordsFromIndex
to posFromIndex,
add indexFromPos
method.21-11-2011: Version 2.18:
Fixes TextMarker.clear, which is broken in 2.17.
21-11-2011: Version 2.17:
setBookmark method.lib/util.27-10-2011: Version 2.16:
coordsFromIndex method.setValue now no longer clears history. Use clearHistory for that.markText now
returns an object with clear and find
methods. Marked text is now more robust when edited.26-09-2011: Version 2.15:
Fix bug that snuck into 2.14: Clicking the character that currently has the cursor didn't re-focus the editor.
26-09-2011: Version 2.14:
fixedGutter option.setValue breaking cursor movement.23-08-2011: Version 2.13:
getGutterElement to API.smartHome option.25-07-2011: Version 2.12:
innerHTML for HTML-escaping.04-07-2011: Version 2.11:
replace method to search cursors, for cursor-preserving replacements.getStateAfter API and compareState mode API methods for finer-grained mode magic.getScrollerElement API method to manipulate the scrolling DIV.07-06-2011: Version 2.1:
Add a theme system (demo). Note that this is not backwards-compatible—you'll have to update your styles and modes!
07-06-2011: Version 2.02:
26-05-2011: Version 2.01:
coordsChar now worksonCursorActivity interfered with onChange.onChange."nocursor" mode for readOnly option.onHighlightComplete option.28-03-2011: Version 2.0:
CodeMirror 2 is a complete rewrite that's faster, smaller, simpler to use, and less dependent on browser quirks. See this and this for more information.
22-02-2011: Version 2.0 beta 2:
Somewhat more mature API, lots of bugs shaken out.
17-02-2011: Version 0.94:
tabMode: "spaces" was modified slightly (now indents when something is selected).08-02-2011: Version 2.0 beta 1:
CodeMirror 2 is a complete rewrite of CodeMirror, no longer depending on an editable frame.
19-01-2011: Version 0.93:
save method to instances created with fromTextArea.28-03-2011: Version 1.0:
17-12-2010: Version 0.92:
styleNumbers option is now officially
supported and documented.onLineNumberClick option added.onLoad and
onCursorActivity callbacks. Old names still work, but
are deprecated.11-11-2010: Version 0.91:
toTextArea to update the code in the textarea.noScriptCaching option (hack to ease development).02-10-2010: Version 0.9:
height: "dynamic" more robust.enterMode and electricChars options to make indentation even more customizable.firstLineNumber option.@media rules by the CSS parser.22-07-2010: Version 0.8:
cursorCoords method to find the screen
coordinates of the cursor.height: dynamic mode, where the editor's
height will adjust to the size of its content.toTextArea method in instances created with
fromTextArea.27-04-2010: Version 0.67:
More consistent page-up/page-down behaviour
across browsers. Fix some issues with hidden editors looping forever
when line-numbers were enabled. Make PHP parser parse
"\\" correctly. Have jumpToLine work on
line handles, and add cursorLine function to fetch the
line handle where the cursor currently is. Add new
setStylesheet function to switch style-sheets in a
running editor.
01-03-2010: Version 0.66:
Adds removeLine method to API.
Introduces the PLSQL parser.
Marks XML errors by adding (rather than replacing) a CSS class, so
that they can be disabled by modifying their style. Fixes several
selection bugs, and a number of small glitches.
12-11-2009: Version 0.65:
Add support for having both line-wrapping and
line-numbers turned on, make paren-highlighting style customisable
(markParen and unmarkParen config
options), work around a selection bug that Opera
reintroduced in version 10.
23-10-2009: Version 0.64:
Solves some issues introduced by the
paste-handling changes from the previous release. Adds
setSpellcheck, setTextWrapping,
setIndentUnit, setUndoDepth,
setTabMode, and setLineNumbers to
customise a running editor. Introduces an SQL parser. Fixes a few small
problems in the Python
parser. And, as usual, add workarounds for various newly discovered
browser incompatibilities.
31-08-2009: Version 0.63:
Overhaul of paste-handling (less fragile), fixes for several serious IE8 issues (cursor jumping, end-of-document bugs) and a number of small problems.
30-05-2009: Version 0.62:
Introduces Python
and Lua parsers. Add
setParser (on-the-fly mode changing) and
clearHistory methods. Make parsing passes time-based
instead of lines-based (see the passTime option).
So you found a problem in CodeMirror. By all means, report it! Bug reports from users are the main drive behind improvements to CodeMirror. But first, please read over these points:
There are a few things in the 2.2 release that require some care when upgrading.
The default theme is now included
in codemirror.css, so
you do not have to included it separately anymore. (It was tiny, so
even if you're not using it, the extra data overhead is negligible.)
CodeMirror has moved to a system where keymaps are used to bind behavior to keys. This means custom bindings are now possible.
Three options that influenced key
behavior, tabMode, enterMode,
and smartHome, are no longer supported. Instead, you can
provide custom bindings to influence the way these keys act. This is
done through the
new extraKeys
option, which can hold an object mapping key names to functionality. A
simple example would be:
extraKeys: {
"Ctrl-S": function(instance) { saveText(instance.getValue()); },
"Ctrl-/": "undo"
}
Keys can be mapped either to functions, which will be given the
editor instance as argument, or to strings, which are mapped through
functions through the CodeMirror.commands table, which
contains all the built-in editing commands, and can be inspected and
extended by external code.
By default, the Home key is bound to
the "goLineStartSmart" command, which moves the cursor to
the first non-whitespace character on the line. You can set do this to
make it always go to the very start instead:
extraKeys: {"Home": "goLineStart"}
Similarly, Enter is bound
to "newlineAndIndent" by default. You can bind it to
something else to get different behavior. To disable special handling
completely and only get a newline character inserted, you can bind it
to false:
extraKeys: {"Enter": false}
The same works for Tab. If you don't want CodeMirror
to handle it, bind it to false. The default behaviour is
to indent the current line more ("indentMore" command),
and indent it less when shift is held ("indentLess").
There are also "indentAuto" (smart indent)
and "insertTab" commands provided for alternate
behaviors. Or you can write your own handler function to do something
different altogether.
Handling of tabs changed completely. The display width of tabs can
now be set with the tabSize option, and tabs can
be styled by setting CSS rules
for the cm-tab class.
The default width for tabs is now 4, as opposed to the 8 that is
hard-wired into browsers. If you are relying on 8-space tabs, make
sure you explicitly set tabSize: 8 in your options.
Version 3 does not depart too much from 2.x API, and sites that use CodeMirror in a very simple way might be able to upgrade without trouble. But it does introduce a number of incompatibilities. Please at least skim this text before upgrading.
Note that version 3 drops full support for Internet Explorer 7. The editor will mostly work on that browser, but it'll be significantly glitchy.
This one is the most likely to cause problems. The internal structure of the editor has changed quite a lot, mostly to implement a new scrolling model.
Editor height is now set on the outer wrapper element (CSS
class CodeMirror), not on the scroller element
(CodeMirror-scroll).
Other nodes were moved, dropped, and added. If you have any code that makes assumptions about the internal DOM structure of the editor, you'll have to re-test it and probably update it to work with v3.
See the styling section of the manual for more information.
In CodeMirror 2.x, there was a single gutter, and line markers
created with setMarker would have to somehow coexist with
the line numbers (if present). Version 3 allows you to specify an
array of gutters, by class
name,
use setGutterMarker
to add or remove markers in individual gutters, and clear whole
gutters
with clearGutter.
Gutter markers are now specified as DOM nodes, rather than HTML
snippets.
The gutters no longer horizontally scrolls along with the content.
The fixedGutter option was removed (since it is now the
only behavior).
<style>
/* Define a gutter style */
.note-gutter { width: 3em; background: cyan; }
</style>
<script>
// Create an instance with two gutters -- line numbers and notes
var cm = new CodeMirror(document.body, {
gutters: ["note-gutter", "CodeMirror-linenumbers"],
lineNumbers: true
});
// Add a note to line 0
cm.setGutterMarker(0, "note-gutter", document.createTextNode("hi"));
</script>
Most of the onXYZ options have been removed. The same
effect is now obtained by calling
the on method with a string
identifying the event type. Multiple handlers can now be registered
(and individually unregistered) for an event, and objects such as line
handlers now also expose events. See the
full list here.
(The onKeyEvent and onDragEvent options,
which act more as hooks than as event handlers, are still there in
their old form.)
cm.on("change", function(cm, change) {
console.log("something changed! (" + change.origin + ")");
});
The markText method
(which has gained some interesting new features, such as creating
atomic and read-only spans, or replacing spans with widgets) no longer
takes the CSS class name as a separate argument, but makes it an
optional field in the options object instead.
// Style first ten lines, and forbid the cursor from entering them
cm.markText({line: 0, ch: 0}, {line: 10, ch: 0}, {
className: "magic-text",
inclusiveLeft: true,
atomic: true
});
The interface for hiding lines has been
removed. markText can
now be used to do the same in a more flexible and powerful way.
The folding script has been updated to use the new interface, and should now be more robust.
// Fold a range, replacing it with the text "??"
var range = cm.markText({line: 4, ch: 2}, {line: 8, ch: 1}, {
replacedWith: document.createTextNode("??"),
// Auto-unfold when cursor moves into the range
clearOnEnter: true
});
// Get notified when auto-unfolding
CodeMirror.on(range, "clear", function() {
console.log("boom");
});
The setLineClass method has been replaced
by addLineClass
and removeLineClass,
which allow more modular control over the classes attached to a line.
var marked = cm.addLineClass(10, "background", "highlighted-line");
setTimeout(function() {
cm.removeLineClass(marked, "background", "highlighted-line");
});
All methods that take or return objects that represent screen
positions now use {left, top, bottom, right} properties
(not always all of them) instead of the {x, y, yBot} used
by some methods in v2.x.
Affected methods
are cursorCoords, charCoords, coordsChar,
and getScrollInfo.
The matchBrackets
option is no longer defined in the core editor.
Load addon/edit/matchbrackets.js to enable it.
The CodeMirror.listModes
and CodeMirror.listMIMEs functions, used for listing
defined modes, are gone. You are now encouraged to simply
inspect CodeMirror.modes (mapping mode names to mode
constructors) and CodeMirror.mimeModes (mapping MIME
strings to mode specs).
Some more reasons to upgrade to version 3.
CodeMirror.defineOption.CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is specialized for editing code, and comes with a number of language modes and addons that implement more advanced editing functionaly.
A rich programming API and a CSS theming system are available for customizing CodeMirror to fit your application, and extending it with new functionality.
CodeMirror is an open-source project shared under an MIT license. It is the editor used in Light Table, Adobe Brackets, Google Apps Script, Bitbucket, and many other projects.
Development and bug tracking happens on github (alternate git repository). Please read these pointers before submitting a bug. Use pull requests to submit patches. All contributions must be released under the same MIT license that CodeMirror uses.
Discussion around the project is done on a mailing list. There is also the codemirror-announce list, which is only used for major announcements (such as new versions). If needed, you can contact the maintainer directly.
A list of CodeMirror-related software that is not part of the main distribution is maintained on our wiki. Feel free to add your project.
The desktop versions of the following browsers,
in standards mode (HTML5 <!doctype html>
recommended) are supported:
| Firefox | version 3 and up |
|---|---|
| Chrome | any version |
| Safari | version 5.2 and up |
| Internet Explorer | version 8 and up |
| Opera | version 9 and up |
Modern mobile browsers tend to partly work. Bug reports and patches for mobile support are welcome, but the maintainer does not have the time or budget to actually work on it himself.
Simple mode that tries to handle APL as well as it can.
It attempts to label functions/operators based upon monadic/dyadic usage (but this is far from fully fleshed out). This means there are meaningful classnames so hover states can have popups etc.
MIME types defined: text/apl (APL code)
MIME types defined: text/x-asterisk.
Simple mode that tries to handle C-like languages as well as it
can. Takes two configuration parameters: keywords, an
object whose property names are the keywords in the language,
and useCPP, which determines whether C preprocessor
directives are recognized.
MIME types defined: text/x-csrc
(C code), text/x-c++src (C++
code), text/x-java (Java
code), text/x-csharp (C#).
MIME types defined: text/x-clojure.
Select Theme Select Font Size
MIME types defined: text/x-coffeescript.
The CoffeeScript mode was written by Jeff Pickhardt (license).
MIME types defined: text/x-common-lisp.
MIME types defined: text/css.
MIME types defined: text/scss.
Simple mode that handle D-Syntax (DLang Homepage).
MIME types defined: text/x-d
.
MIME types defined: text/x-diff.
MIME types defined: application/xml-dtd.
Based on CodeMirror's clike mode. For more information see HPCC Systems web site.
MIME types defined: text/x-ecl.
MIME types defined: text/x-eiffel.
Created by YNH.
MIME types defined: text/x-erlang.
MIME types defined: text/x-Fortran.
Handles AT&T assembler syntax (more specifically this handles
the GNU Assembler (gas) syntax.)
It takes a single optional configuration parameter:
architecture, which can be one of "ARM",
"ARMv6" or "x86".
Including the parameter adds syntax for the registers and special
directives for the supplied architecture.
MIME types defined: text/x-gas
Optionally depends on other modes for properly highlighted code blocks.
MIME types defined: text/x-feature.
MIME type: text/x-go
MIME types defined: text/x-groovy
MIME types defined: text/x-haml.
MIME types defined: text/x-haskell.
MIME types defined: text/x-haxe.
Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on
JavaScript, CSS and XML.
Other dependancies include those of the scriping language chosen.
MIME types defined: application/x-aspx (ASP.NET),
application/x-ejs (Embedded Javascript), application/x-jsp (JavaServer Pages)
The HTML mixed mode depends on the XML, JavaScript, and CSS modes.
It takes an optional mode configuration
option, scriptTypes, which can be used to add custom
behavior for specific <script type="..."> tags. If
given, it should hold an array of {matches, mode}
objects, where matches is a string or regexp that
matches the script type, and mode is
either null, for script types that should stay in
HTML mode, or a mode
spec corresponding to the mode that should be used for the
script.
MIME types defined: text/html
(redefined, only takes effect if you load this parser after the
XML parser).
MIME types defined: message/http.
This is a list of every mode in the distribution. Each mode lives
in a subdirectory of the mode/ directory, and typically
defines a single JavaScript file that implements the mode. Loading
such file will make the language available to CodeMirror, through
the mode
option.
Created by Drew Bratcher. Managed as part of an Adobe Brackets extension at https://github.com/dbratcher/brackets-jade.
MIME type defined: text/x-jade.
JavaScript mode supports a two configuration options:
json which will set the mode to expect JSON
data rather than a JavaScript program.typescript which will activate additional
syntax highlighting and some other things for TypeScript code
(demo).statementIndent which (given a number) will
determine the amount of indentation to use for statements
continued on a new line.MIME types defined: text/javascript, application/json, text/typescript, application/typescript.
This is a specialization of the JavaScript mode.
MIME types defined: text/x-less, text/css (if not previously defined).
MIME types defined: text/x-livescript.
The LiveScript mode was written by Kenneth Bentley (license).
Loosely based on Franciszek
Wawrzak's CodeMirror
1 mode. One configuration parameter is
supported, specials, to which you can provide an
array of strings to have those identifiers highlighted with
the lua-special style.
MIME types defined: text/x-lua.
Optionally depends on the XML mode for properly highlighted inline XML blocks.
MIME types defined: text/x-markdown.
MIME types defined: text/mirc.
MIME types defined: text/nginx.
MIME types defined: text/n-triples.
MIME types defined: text/x-ocaml.
MIME types defined: text/x-octave.
MIME types defined: text/x-pascal.
MIME types defined: text/x-perl.
Simple HTML/PHP mode based on the C-like mode. Depends on XML, JavaScript, CSS, HTMLMixed, and C-like modes.
MIME types defined: application/x-httpd-php (HTML with PHP code), text/x-php (plain, non-wrapped PHP code).
Simple mode that handles Pig Latin language.
MIME type defined: text/x-pig
(PIG code)